1. 程式人生 > 實用技巧 >【NOIP2017提高A組模擬9.17】信仰是為了虛無之人

【NOIP2017提高A組模擬9.17】信仰是為了虛無之人

【NOIP2017提高A組模擬9.17】信仰是為了虛無之人

Description

Input

Output

Sample Input

3 3 0
1 1 7
1 1 6
1 3 2

Sample Output

1
0
1
7
0
5

Data Constraint

題解

判斷真假考慮並查集,設\(g[i]\)表示從當前這棵樹的根到\(i\)的字首異或值,那麼對於當前這個區間,\(l-1\)\(r\)討論
\(f1\)\(l-1\)的根,\(f2\)\(r\)的根

  • 如果\(f1=f2\),說明是同一棵樹,那麼只有\(k=g[r]\ xor\ g[l-1]\)成立的時候才是真
  • 如果\(f1!=f2\)
    ,肯定是真,然後考慮合兩棵樹並,把\(f1\)\(f2\)裡較大的接到較小的,然後\(g[f2]=g[f2]\ xor\ g[l-1]\ xor\ g[r]\ xor\ k\),因為要使接上去之後異或值是\(k\)

在並查集\(find\)的時候同時更新\(g[i]\)
\(s[i]\)表示\(1\)~\(i-1\)的最小異或值
求最小值時,如果當前這個點是祖先,說明這個點的取值沒有限制,自然取0最優:\(s[i]=s[i-1]\)。如果不是祖先,那麼這個點要填的就是\(g[i]\)\(s[i]=s[find(i)]^\ xor\ g[i]\)
輸出\(s[i]\ xor\ s[i-1]\)

Code

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,pd,l,r,k,last,f1,f2,x,f[200001],g[200001],sum[200001];
int read()
{
	int res=0,fh=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') fh=-1,ch=getchar();
	while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch-'0'),ch=getchar();
	return res*fh;
}
int find(int x)
{
	if (f[x]==x) return x;
	int xx=find(f[x]);
	g[x]^=g[f[x]];
	return f[x]=xx;
}
int main()
{
	freopen("sanae.in","r",stdin);
	freopen("sanae.out","w",stdout);
	n=read();m=read();pd=read();
	for (int i=1;i<=n;++i)
		f[i]=i;
	while (m--)
	{
		l=read();r=read();k=read();
		if (pd) l^=last,r^=last,k^=last;
		f1=find(l-1);f2=find(r);
		if (f1==f2)
		{
			if ((g[l-1]^g[r])==k) last=1;
			else last=0;
			printf("%d\n",last);			
		}
		else
		{
			if (f1>f2) swap(f1,f2);
			f[f2]=f1;
			g[f2]^=g[l-1]^g[r]^k;
			last=1;
			printf("%d\n",last);
		}
	}
	for (int i=1;i<=n;++i)
	{
		x=find(i);
		if (i==x) sum[i]=sum[i-1];
		else sum[i]=sum[x]^g[i];
		printf("%d\n",sum[i]^sum[i-1]);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}