题解 P4151 [WC2011] 最大XOR和路径

前言

洛谷紫题 acwing 你告诉我是普通?!

Sol

题目是连通图。

考虑对于一个环,我们可以取任意次环中的异或和,因为我们只要转一圈即可。我们需要求的是 \(1\)\(n\) 的不必简单路径使得异或和最大。考虑对于 \(1\)\(n\) 的路径中经过的所有环,那么就考虑遍历所有从 \(1\) 开始所有的路径,如果有一个点能通过两个不同的边到达且那两边所到的点联通,那么就证明有一个环。而我们在从 \(1\) 开始的 DFS 序遍历时遍历到两次同一个点就是这种情况,即我们的重点由两条有共同源的路径遍历而来。知识点:DFS 求环

\(n\) 可以到任意环,并且一来一回不会异或到环的路径,并且对与任意两条由 \(1\)\(n\) 的路线,都构成一个大环,所以只根据 DFS 序到 \(n\) 的异或和,是没有任何问题的,因为可以替换。

找出所有的环,做线性基,最后根据 DFS 序到 \(n\) 的异或和来异或即可。

异或线性基后所有的值二进制最高位唯一,贪心即可。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e4+5,M=2e5+5;
int h[N],e[M],ne[M],w[M],d[N],idx;
bool st[N];
vector<int> loops;
int n,m;
void add(int a,int b,int c) {
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
void dfs(int u) {
	st[u]=1;
	for(int i=h[u];i!=-1;i=ne[i]) {
		int j=e[i];
		if(!st[j]) {//从未到达过的点,d[x]表示dfs序更新时的前缀异或和。 
			d[j]=d[u]^w[i];
			dfs(j);
		}
		else {//到达过的点,那么两条所经路线的不交集就构成了一个环,环值即为 
			int tmp=d[j]^d[u]^w[i];
			loops.push_back(tmp);
		}
	}
}
signed main() {
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i=1;i<=m;i++) {
        int x,y,z;cin>>x>>y>>z;
        add(x,y,z),add(y,x,z);
    }
    dfs(1);
    int sz=loops.size();
    for(int i=0;i<loops.size();i++) {
    	for(int j=i+1;j<loops.size();j++) if(loops[j]>loops[i]) swap(loops[i],loops[j]);
    	if(!loops[i]) {sz=i;break;}
    	for(int j=62;j>=0;j--)
    		if((loops[i]>>j)&1) {
    			for(int k=0;k<loops.size();k++) if(k!=i&&((loops[k]>>j)&1)) loops[k]^=loops[i];
				break;
			}
	}
	int res=d[n];
	for(int i=0;i<sz;i++)
		for(int j=62;j>=0;j--)
			if((loops[i]>>j)&1) {
				if(!((res>>j)&1)) res^=loops[i];
				break;
			}
	cout<<res<<endl;
    return 0;
}
posted @ 2024-09-18 18:07  PM_pro  阅读(13)  评论(0)    收藏  举报