|
思路:
這題是道好題! 假比確定了 [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;
}

|