|
思路:
这题是道好题! 假比确定了 [2, 4]、[5, 6]、[7, 8] 的奇偶性 [4, 5] 的奇偶性无法得知 [2, 6] 的奇偶性是知道的 所以只有询问的区间符合以下要求: 1. 头部和某个已知区间的头部重合 2. 尾部和某个已知区间的尾部重合 3. 区间内每一段都是已知的 才能得出结论
我只想到这一步,然后用链表写了一遍,TLE 了。上网搜解题报告,看到“并查集”三字,恍然大悟。吗的太牛逼了。
我们把首尾相接的多个已知区间归为一类。 将这多个区间的尾部的点归在同一个集合中。 它们的父亲就是最左边区间头部。 它们的权值就是从左边区间头部的到自己的这段区间的奇偶性。
插入区间 [i, j] 的时候,首先查找 i, j 对应的父亲。就是 find 操作。 如果它们的父亲相同,则表明它们处在同一个段的多个已知区间中。 那么 i, j 的权值相减,就很容易得出 [i, j] 的奇偶性了。 如果它们的父亲不同,则需要将 i, j 分别对应的区间段关联起来。也就是 union 操作。 这时候要注意判断 i, j 父亲的位置先后。因为这个 WA 了一次。
由于节点的位置分得很散,用 hash 存放。
#include <stdio.h>

#define HASH_SIZE (1 << 18)
#define NODES_NR 65536

 struct node {
struct node *root, *next;
int idx, val;
};

struct node *hash[HASH_SIZE], nodes[NODES_NR];
int nodes_cnt;

inline void find(struct node *t)
  {
static struct node *stk[NODES_NR];
int i;

for (i = 0; t->root != t; t = t->root)
stk[i++] = t;
 for (i--; i >= 0; i--) {
stk[i]->val += stk[i]->root->val;
stk[i]->root = t;
}
}

inline struct node *insert(int idx)
  {
int h;
struct node *t;

h = idx & (HASH_SIZE - 1);
 for (t = hash[h]; t; t = t->next) {
if (t->idx == idx)
break;
}
 if (!t) {
t = &nodes[nodes_cnt++];
t->root = t;
t->idx = idx;
t->next = hash[h];
hash[h] = t;
}
return t;
}

inline int solve(int start, int end, int val)
  {
struct node *a, *b;

a = insert(start);
b = insert(end);
find(a);
find(b);

if (a->root == b->root)
return ((b->val - a->val) & 1) == val;

val -= b->val;
val += a->val;
a = a->root;
b = b->root;
 if (a->idx < b->idx) {
b->root = a;
b->val = val;
 } else {
a->root = b;
a->val = -val;
}

return 1;
}

int main()
  {
int n, i, x, a, b;
char str[16];

freopen("e:\\test\\in.txt", "r", stdin);

scanf("%d%d", &n, &x);
 for (i = 0; i < x; i++) {
scanf("%d%d%s", &a, &b, str);
if (!solve(a, b + 1, str[0] == 'o'))
break;
}
printf("%d\n", i);

return 0;
}

|