E-min of restricted sum

题目链接:https://atcoder.jp/contests/abc396/tasks/abc396_e

题意:

给定x,y,z序列要求构造一个a序列使a[xi]^a[yi]=z[i]对于每个i都成立且a的元素相加尽量小

思路:

将每个xi和yi当作两个结点,在两者间构建无向边,权值为zi

那么我们就发现这些xi和yi的关系是一些连通块(从起点出发确定块内所有点)

我们先固定一个连通块的一个起点,假设它为u,有两条边的关系:u - >v,u -> r- >t -> v
递推可得
第一条:a[xu] ^ a[xv] =z [uv] -> a[xu] =a[xv] ^z[uv]
第二条:a[xu] = z[ur]^ z[rt]^ a[xv]
因此发现为了不矛盾,我们需要使从起点出发到达的点 所经过路径异或和 一致
所以当再次搜索到了某个点只需与之前路径异或和进行比较就可以,若相同则不矛盾

为了构造使得sum【a】最小,我们把ai的值拆成二进制来分析

(需要先确定一点,然后连通块其他的点就确定了)

那么对于起点ai,令其大小为k,那么其他节点的大小= ai^路径异或和w

对于每一位,如果这些路径异或和w 1的个数多,说明ai这一位取1比较划算(因为异或),同理0个数多,就取0

最后对于一个连通块确定起点进行dfs就可以确定其他点

题目应该给的是多个连通块,这点要注意

还有要开ll

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define pb push_back
#define endl "\n"
#define fi first
#define int long long
#define se second
//#pragma GCC optimize(3)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const ll llmax=LLONG_MAX;
const int maxn=2e5+5;
const int mod=1e9+7;
struct edge{
	int to;int w;
};
vector<edge>g[maxn];
int vis[maxn];
int val[maxn];
int cnt;
int a[maxn];
vector<int>bt(33);
void dfs(int u,int cur,int fa){
	cnt++;
	vis[u]=1;
	val[u]=cur;
	
	for(int i=0;i<32;i++){
		if(cur&(1<<i)){
			bt[i]++;
		}
	}
	
	
	for(auto ed:g[u]){
		int v=ed.to,w=ed.w;
		if(v!=fa){
		if(vis[v]){
			if(val[v]!=(cur^w)){
				cout<<-1<<endl;
				exit(0);
			}
		}else{
			dfs(v,cur^w,u);
		}
		}
	}
}
void dfs2(int u){
	vis[u]=1;
	for(auto ed:g[u]){
		int v=ed.to,w=ed.w;
		if(!vis[v]){
			a[v]=a[u]^w;
			dfs2(v);
		}
	}
}
void solve(){
	int n,m;cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,y,z;cin>>x>>y>>z;
		g[x].pb({y,z});
		g[y].pb({x,z});
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			cnt=0;
			dfs(i,0,0);
			for(int j=0;j<32;j++){
				if(bt[j]>=cnt-bt[j]){
					a[i]=a[i]|(1<<j);
				}
				bt[j]=0;
			}
		}
	}
	
	memset(vis,0,sizeof(vis));
	
	for(int i=1;i<=n;i++)if(!vis[i]){
		dfs2(i);
	}
	for(int i=1;i<=n;i++)cout<<a[i]<<' ';
	
}

signed main()
{
	ios::sync_with_stdio(false),cin.tie(0);
	int T=1;
	
	while(T--){
	solve();
	}
	
	return 0;
}


posted @ 2025-03-10 17:07  Marinaco  阅读(86)  评论(0)    收藏  举报
//雪花飘落效果