首页 > 其他分享 >Codeforces Round #851 (Div. 2)-F. XOR, Tree, and Queries-树、异或、并查集

Codeforces Round #851 (Div. 2)-F. XOR, Tree, and Queries-树、异或、并查集

时间:2023-02-12 15:11:06浏览次数:63  
标签:XOR 851 int rep 查集 fa 异或 oplus itr

题目:https://codeforces.com/contest/1788/problem/F

题解:
(首先他和线性基没什么瓜系)
想这个问题大概可以分成几个部分:

  • 1、很自然地考虑记\(p_x\)表示从根节点走到x路径上边的异或和,那么每个约数:u到v的路径异或和恰为x,可以表示为\(p_u\oplus p_v\oplus p_{lca}\oplus p_{lca}=p_u\oplus p_v =x\),一定要注意LCA需要扣掉两次,这很关键。
  • 2、考虑\(p_u\oplus p_v=x\)如何表示,可以建另一张图\(G_2\),在这张图上\((u,v)\)的边权x就表示\(p_u\oplus p_v\)恰好为x。
  • 3、如何check是否合法?由于会由\(G_2\)若干连通块组成,每个连通块相互独立,对每个连通块任取一个节点开始dfs,给块内每个点附一个符合约束的值,因为异或和其实就只是一个相对关系,所以一旦出现某个\((u,v),(v,w)\)的边权异或不等于\((u,w)\)的边权时就无解,否则一定有解
  • 4、如何保证最后的异或和最小?这里再去考虑边权异或如何用\(p\)数组表示,很容易发现所有奇度点对应的p的异或和就是所有边权的异或(而偶度点总会被重复计算),所以答案就很明确了:我们先把所有奇度点的p值全部异或起来,得到一个sum,然后再去寻找有没有哪个连通块恰有奇数个奇度点,如果有的话就给这个连通块的p全部异或上sum,这样就能得到0的答案;否则如果找不到这样的连通块,sum自然就是唯一解了。
    连通块以及点的个数
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define mp make_pair
typedef long long ll;
using namespace std;
const int N=250005;
int n,q,a[N],p[N],deg[N],fa[N],cnt[N],vis[N];
vector<vector<pair<int,int>>> G1,G2;
int find(int x){
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
void merge(int x,int y){
	int fx=find(x),fy=find(y);
	if(fx==fy)return;
	fa[fy]=fx;cnt[fx]^=cnt[fy];
}
void dfs(int x,int d){
	vis[x]=1;p[x]=d;
	for(auto itr:G2[x]){
		int to=itr.first;
		if(!vis[to])dfs(to,d^itr.second);
	}
}
void dfs2(int x,int fa){
	for(auto itr:G1[x]){
		int to=itr.first;
		if(to==fa)continue;
		dfs2(to,x);
		a[itr.second]=(p[x]^p[to]);
	}
}
int main(){
	fastio;
	cin>>n>>q;
	G1.resize(n+1);G2.resize(n+1);
	rep(i,1,n)fa[i]=i;
	rep(i,1,n-1){
		int u,v;cin>>u>>v;
		G1[u].push_back(mp(v,i));
		G1[v].push_back(mp(u,i));
		deg[u]^=1;deg[v]^=1;
	}
	rep(i,1,n)cnt[i]=deg[i];
	while(q--){
		int u,v,x;cin>>u>>v>>x;
		G2[u].push_back(mp(v,x));
		G2[v].push_back(mp(u,x));
		merge(u,v); 
	}
	rep(i,1,n)if(!vis[i])dfs(i,0);
	bool ok=1;
	rep(i,1,n)for(auto itr:G2[i]){
		int to=itr.first,w=itr.second;
		if((p[i]^p[to])!=w)ok=0;
	}
	if(!ok)cout<<"No"<<endl;
	else{
		cout<<"Yes"<<endl;
		int sum=0;
		rep(i,1,n)if(deg[i]==1)sum^=p[i];
		rep(i,1,n)if(cnt[find(i)]==1){
			int x=find(i);
			rep(j,1,n)if(find(j)==x)p[j]^=sum;
			break;
		}
		dfs2(1,-1);
		rep(i,1,n-1)cout<<a[i]<<' ';
	}
	return 0;
}

标签:XOR,851,int,rep,查集,fa,异或,oplus,itr
From: https://www.cnblogs.com/yoshinow2001/p/17113834.html

相关文章

  • Codeforces Round #851 (Div. 2) D
    链接:https://codeforces.com/contest/1788/problem/D题意:数轴上有n个点,每个点会以相同的v向最近的点移动(若左右距离相等则向左),两点相遇则暂停,问最终数轴上剩下的点数即为......
  • 「AcWing学习记录」并查集
    并查集1.将两个集合合并2.询问两个元素是否在一个集合当中时间复杂度近乎O(1)基本原理每个集合用一棵树来表示。树根的编号就是整个集合的编号,每个节点存储它的父节点......
  • Codeforces Round #851 (Div. 2) A-E
    比赛链接A题意给一串只包含\(1,2\)的数,找到最小的\(k\)使得\(\prod_{i=1}^ka_i=\prod_{i=k+1}^na_i\)。题解知识点:枚举。因为只有\(1,2\),所以考虑左右两......
  • 并查集
    一、什么是并查集什么是并查集?字面意思把一堆东西  合并  、  查找二、并查集讲解前置知识点1.可以把并查集的实现理解为在合并几棵树2.需要用到fa数组,fa[i......
  • Codeforces Round #851 (Div. 2)
    A.OneandTwo比较两边\(2\)的个数即可。#include<bits/stdc++.h>usingnamespacestd;intn,T,prefix[1111],suffix[1111],ans,a[1111];intmain(){sc......
  • 2.10 Codeforces Round #851 (Div. 2)
    A-OneandTwo题意给出长度为n的序列a,a中元素是1或2找到一个k使a1*a2*a3*....*ak=ak+1*ak+2*ak+3*...*an思路统计序列中有多少个2,若是奇数个2,则......
  • 并查集
    并查集大佬笔记如下:通俗易懂https://zhuanlan.zhihu.com/p/93647900并查集是什么?主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作:合并:把......
  • Codeforces Round #851 (Div. 2) 题解
    CodeforcesRound#851(Div.2)题解A.OneandTwo取\(\log_2\),变成加号,前缀和枚举\(s[i]=\dfrac{s[n]}{2}\)。B.SumofTwoNumbers对于每一位,如果是偶数则平均......
  • ZYB loves Xor I HDU - 5269(01字典树,二进制,异或,lowbit)
    题意:给出一列数,求任意两个数的异或值得lowbit值和。PS:一个数的lowbit为,第一个不为0的数前有k个0,则为2^k。题解:利用字典树存储这些数的二进制,每次插入将相应的异或的lowbit......
  • 【YBT2023寒假Day8 C】图论题(图论)(并查集)(线段树合并)
    图论题题目链接:YBT2023寒假Day8C题目大意给你一个无向图,然后你会一直操作直到无法操作,每次找出一个满足条件的三元组(a,b,c),满足a<b<c,a,b与a,c之间有边,b,c之间没......