专栏文章

题解:CF1044D Deduction Queries

CF1044D题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min3vud5
此快照首次捕获于
2025/12/01 20:08
3 个月前
此快照最后确认于
2025/12/01 20:08
3 个月前
查看原文

Sol

奶龙题,区间异或等价转化为前缀和的两个点异或,由于异或操作很好的性质直接带权并查集一下,能判断区间和当且仅当前缀和对应端点在同一连通块,直接查到根的异或和异或一下即可。
详细解释一部分:
  • 不难发现,原先应当在并查集上查二者的路径的异或和,但是直接全部查到根也无妨,重合的部分会抵消掉。
  • 使用并查集的正确性显然:两个区间端点重合,若二者不重叠,他们的并可求;若二者重叠,他们的对称差可求。并且由于是异或操作,所以很方便处理信息传递,无脑异或就行。
更多细节就详见代码吧,关于带权并查集的详细实现可以参阅相应模板题。

Code

CPP
const int N=4e5+5;

int q,n;
map<int,int> id;

int fa[N],rk[N],vl[N];
pii find(int x){int res=0;while(x!=fa[x])res^=vl[x],x=fa[x];return {x,res};}
void merge(int a,int b,int c){
	auto [x,vx]=find(a);auto [y,vy]=find(b);
	if(x==y)return;
	if(rk[x]>rk[y])swap(x,y),swap(vx,vy);
	c^=vx^vy;
	// cerr<<x<<"--->"<<y<<" "<<c<<"\n";
	fa[x]=y,rk[y]+=rk[x];vl[x]=c;
}
bool same(int a,int b){
	auto [x,vx]=find(a);auto [y,vy]=find(b);
	return x==y;
}

inline void Main(){
	cin>>q;
	int ans=0;
	rep(i,1,q){
		int t;cin>>t;
		if(t==1){
			int l,r,x;cin>>l>>r>>x;
			l^=ans,r^=ans,x^=ans;
			if(l>r)swap(l,r);
			if(!id[l-1])id[l-1]=++n,fa[n]=n,rk[n]=1;
			if(!id[r])id[r]=++n,fa[n]=n,rk[n]=1;
			merge(id[l-1],id[r],x);
		}else{
			int l,r;cin>>l>>r;
			l^=ans,r^=ans;
			if(l>r)swap(l,r);
			if(!id[l-1]||!id[r]||!same(id[l-1],id[r])){
				put(-1);
				ans=1;
			}else{
				ans=find(id[l-1]).sec,ans^=find(id[r]).sec;
				put(ans);
			}
		}
	}
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...