2018.09.25【BZOJ2115】【洛谷P4151】【WC2011】最大XOR和路径(线性基)

BZOJ传送门

洛谷传送门


解析:

额这道题可能是 W C WC WC场上的签到题。
但不知道为什么被标成了黑题。。。

感觉不是一般 W C WC WC的水平啊。
太简单了一点吧。。。

思路:

我们发现,重复的走过同一条路径对答案是没有任何贡献的。异或的自反性使得这道题十分的奇妙。

我们随便记录每个点到1的任意一条路径的前缀异或和。发现当我们随便选出一条从1到 n n n的路径之后,只有与1或 n n n联通的环能够更新答案。

并且这个更新答案是任意更新。

显而易见,线性基。

具体做法就是利用 D F S DFS DFS或者 B F S BFS BFS,处理出所有点到1的任意路径,同时找出所有的环,并将环扔进线性基里面。如果把线性基的构建当做常数时间的话,那么这里的的复杂度就只有 O ( V + E ) O(V+E) O(V+E)

我们已经处理出了所有能够用于更新答案的环,那么我们取出任意一条1到 n n n的路径,丢到线性基里面,算出最大的答案。环的权值可以用差分来计算。

notes:

顺便提一下,为什么能够随便取路径。

首先,如果这是唯一路径,自然不用多说。

如果有多条路径,则必然存在环。
那环已经被丢到线性基里面了啊。

我们在线性基里面异或就可以取出最优的答案了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
ll getint(){
	re ll num;
	re char c;
	while(!isdigit(c=gc()));
	num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

ll b[64];
inline
void insert(ll a){
	if(a)
	for(int re i=62;~i;--i){
		if(a&(1ll<<i))
		if(!b[i]){
			b[i]=a;
			break;
		}
		else a^=b[i];
	}
}

inline ll query(ll a){
	for(int re i=62;~i;--i)
	if((a^b[i])>a)a^=b[i];
	return a;
}

cs int N=50001,M=100003;
int last[N],nxt[M<<1],to[M<<1],ecnt;
ll w[M<<1];
inline
void addedge(int u,int v,ll val){
	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
	nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u,w[ecnt]=val;
}

ll dist[N];
bool vis[N];

int n,m;

inline
void dfs(int u,ll res){
	vis[u]=true;
	dist[u]=res;
	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
	if(!vis[v])dfs(v,res^w[e]);
	else insert(res^w[e]^dist[v]);
}

signed main(){
	n=getint(),m=getint();
	for(int re i=1;i<=m;++i){
		int u=getint(),v=getint();
		ll val=getint();
		addedge(u,v,val); 
	}
	dfs(1,0);
	cout<<query(dist[n])<<endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值