[WC2011]最大XOR和路径,洛谷P4151,线性基+Dfs

正题

      这一题挺水的?

      直接随便求一条1到n的路径异或和,建出Dfs树,每一条返祖边与两点之间路径异或和组成环,扔进线性基,最后维护一遍即可。

      首先证明为什么只用扔返祖环和为什么可以扔环?

      先解决第二个问题,每一个环肯定可以从1走到其中的某个点上,遍历一遍这个环,在从开始遍历的那个点回去。

      那么1到这个点就被遍历了两遍,异或和为0,剩下的环算了一次异或值。

      然后解决第一个问题,因为不是返祖环的环可以有返祖环异或而成。很明显,自己画图即可。

      那么我们证明了只有环才能带来价值。

      最后,为什么随便选一条路径?

      因为如果有多条路径,那么他们两两成环,肯定可以异或出来另一条路径。

#include
#include
#include
#include
using namespace std;

int n,m;
struct edge{
	int y,next;
	long long c;
}s[200010];
int first[50010],len=0;
bool tf[50010];
long long dis[50010];
long long p[65];

void ins(int x,int y,long long c){
	len++;
	s[len]=(edge){y,first[x],c};first[x]=len;
}

void insert(long long x){
	for(int i=63;i>=0;i--)
		if(x>>i){
			if(p[i]) x^=p[i];
			else {p[i]=x;break;}
		}
}

void dfs(int x,long long t){
	tf[x]=true;dis[x]=t;
	for(int i=first[x];i!=0;i=s[i].next)
		if(tf[s[i].y]) insert(t^s[i].c^dis[s[i].y]);
		else dfs(s[i].y,dis[x]^s[i].c);
}

int main(){
	scanf("%d %d",&n,&m);
	int x,y;
	long long c;
	for(int i=1;i<=m;i++){
		scanf("%d %d %lld",&x,&y,&c);
		ins(x,y,c);
		ins(y,x,c);
	}
	dfs(1,0);
	long long ans=dis[n];
	for(int i=63;i>=0;i--) ans=max(ans,ans^p[i]);
	printf("%lld",ans);
}

 

你可能感兴趣的:([WC2011]最大XOR和路径,洛谷P4151,线性基+Dfs)