Acwing 239.奇偶游戏(带权值并查集和扩展域并查集)

小A和小B在玩一个游戏。

首先,小A写了一个由0和1组成的序列S,长度为N。

然后,小B向小A提出了M个问题。

在每个问题中,小B指定两个数 l 和 r,小A回答 S[l~r] 中有奇数个1还是偶数个1。

机智的小B发现小A有可能在撒谎。

例如,小A曾经回答过 S[1~3] 中有奇数个1, S[4~6] 中有偶数个1,现在又回答 S[1~6] 中有偶数个1,显然这是自相矛盾的。

请你帮助小B检查这M个答案,并指出在至少多少个回答之后可以确定小A一定在撒谎。

即求出一个最小的k,使得01序列S满足第1~k个回答,但不满足第1~k+1个回答。

输入格式

第一行包含一个整数N,表示01序列长度。

第二行包含一个整数M,表示问题数量。

接下来M行,每行包含一组问答:两个整数l和r,以及回答“even”或“odd”,用以描述S[l~r] 中有偶数个1还是奇数个1。

输出格式

输出一个整数k,表示01序列满足第1~k个回答,但不满足第1~k+1个回答,如果01序列满足所有回答,则输出问题总数量。

数据范围

N1e9,M10000

带权值并查集版本。

 1 #include 
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 
 7 using namespace std;
 8 
 9 const int N = 10010;
10 int p[N];
11 int d[N];
12 unordered_map s;
13 int n, m;
14 
15 int get(int x)
16 {
17     if (s[x] == 0) s[x] = ++ n;
18     return s[x];
19 }
20 
21 int find(int x)
22 {
23     if (p[x] != x)
24     {
25         int u = find(p[x]);
26         d[x] ^= d[p[x]];
27         p[x] = u;
28     }
29     return p[x];
30 }
31 
32 int main()
33 {
34     cin >> n >> m;
35     n = 0;
36     int res = m;
37 
38     for (int i = 0; i < N; i ++ ) p[i] = i;
39 
40     for (int i = 1; i <= m; i ++ )
41     {
42         int a, b; string op;
43         cin >> a >> b >> op;
44         a = get(a - 1), b = get(b);
45 
46         int t = 0;
47         if (op == "odd") t = 1;
48 
49         int fa = find(a), fb = find(b);
50         if (fa == fb)
51         {
52             if (d[a] ^ d[b] != t)
53             {
54                 res = i - 1;
55                 break;
56             }
57         }
58         else
59         {
60             p[fa] = fb;
61             d[fa] = d[a] ^ d[b] ^ t;//这里使用t来约束,使得d数组都是小于2的数
62         }
63     }
64 
65     printf("%d", res);
66     return 0;
67 }

 这里d数组是存储每个点之间的状态。

我们可以用s数组(即d数组)代表序列的前缀和,并且由于有t<2来约束s数组使得我们的s数组的值始终小于1,那么就可以使用异或的性质来判断,那么有:

s[l ~ r] 之间有偶数个1,等价于s[r]与s[l - 1]的奇偶性相同,即d[r] ^ d[l - 1] = 0。

s[l ~ r] 之间有奇数个1,等价于s[r]与s[l - 1]的奇偶性不同,即d[r] ^ d[l - 1] = 1。

一、当两个数奇偶性相同时

1.若两个元素a,b有公共的祖先,即两个元素在同一个集合中时,我们就判断一下d[a] ^ d[b]的值是否为0,若不为0则说明发生了冲突。

2.若两个元素a,b没有公共祖先,即两个元素没有在同一个集合中时,这时我们就不用关心两个元素异或的奇偶性,因为代表这两个元素之前没有被联系到一起,即使两个元素被使用过或者被覆盖掉也不用关心,因为这里没有给出序列的具体演示,那么就有无限种可能,总有一种可能符合。所以我们只需将两个元素联系到一起即可。

二、当两个元素奇偶性不同时

1.若两个元素a,b有公共的祖先,即两个元素在同一个集合中时,我们就判断一下d[a] ^ d[b]的值是否为1,若不为1则说明发生了冲突。

2.同上第一种情况即可。

你可能感兴趣的:(数据结构,java,python,算法,c++)