【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 ] g[i] g[i]表示从当前这棵树的根到 i i i的前缀异或值,那么对于当前这个区间, l − 1 l-1 l1 r r r讨论
f 1 f1 f1 l − 1 l-1 l1的根, f 2 f2 f2 r r r的根

  • 如果 f 1 = f 2 f1=f2 f1=f2,说明是同一棵树,那么只有 k = g [ r ]   x o r   g [ l − 1 ] k=g[r]\ xor\ g[l-1] k=g[r] xor g[l1]成立的时候才是真
  • 如果 f 1 ! = f 2 f1!=f2 f1!=f2,肯定是真,然后考虑合两棵树并,把 f 1 f1 f1 f 2 f2 f2里较大的接到较小的,然后 g [ f 2 ] = g [ f 2 ]   x o r   g [ l − 1 ]   x o r   g [ r ]   x o r   k g[f2]=g[f2]\ xor\ g[l-1]\ xor\ g[r]\ xor\ k g[f2]=g[f2] xor g[l1] xor g[r] xor k,因为要使接上去之后异或值是 k k k

在并查集 f i n d find find的时候同时更新 g [ i ] g[i] g[i]
s [ i ] s[i] s[i]表示 1 1 1~ i − 1 i-1 i1的最小异或值
求最小值时,如果当前这个点是祖先,说明这个点的取值没有限制,自然取0最优: s [ i ] = s [ i − 1 ] s[i]=s[i-1] s[i]=s[i1]。如果不是祖先,那么这个点要填的就是 g [ i ] g[i] g[i] s [ i ] = s [ f i n d ( i ) ]   x o r   g [ i ] s[i]=s[find(i)]^\ xor\ g[i] s[i]=s[find(i)] xor g[i]
输出 s [ i ]   x o r   s [ i − 1 ] s[i]\ xor\ s[i-1] s[i] xor s[i1]

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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值