[WC2011]最大XOR和路径「线性基+图论」
题目描述
思路分析
谁推荐的题怎么全是新知识啊
如果你不会线性基,请出门左转学习这篇博客,然后切掉这道题【模板】线性基再回来看这道题。
- 异或真是个神奇的东西!!!。
- 题目中要求路径必须是从 \(1\) 到 \(n\) 的路径,然后显然这条路径不唯一,不仅如此,还会有环。
- 首先从 \(1\) 进行 \(dfs\) 跑一遍简单路径,并在过程中找出所有的环。当然,不一定遍历到所有的环,但没遍历到的对答案没有影响,因为要求的是 \(1\) 到 \(n\)。
- 考虑这些环可能依附简单路径的上,即可经过可不经过。这种情况很简单,用线性基判断一下经不经过就好了。还有一种情况就是因为一个环的出现而形成了多条简单路径(像钥匙扣一样)。这时候就可以利用异或的性质,因为我们 \(dfs\) 时已经求出了一条简单路径,那么我们用这个环异或一下这个路径就可以得到另一条路径,所以还是可以用线性基处理。
- 最后在概述一下:先 \(dfs\) 求出到达 \(n\) 的简单路径的异或长度并找出途中的环,以简单路径的长度为初始答案,再用线性基拿所有的环长去更新答案就好了
\(Code\)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 200010
#define R register
#define ll long long
using namespace std;
inline ll read(){
ll x = 0,f = 1;
char ch = getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,head[N],tot;
ll circle[N],dis[N],p[N];
bool vis[N];
struct edge{
int to,next;
ll val;
}e[N<<2];
int len;
void addedge(int u,int v,ll w){
e[++len].to = v;
e[len].val = w;
e[len].next = head[u];
head[u] = len;
}
void dfs(int u,int fa){
vis[u] = 1;
for(R int i = head[u];i;i = e[i].next){
int v = e[i].to;
if(v==fa)continue;
if(vis[v]){
circle[++tot] = dis[u]^dis[v]^e[i].val;//环长(指异或和)
continue;
}
dis[v] = dis[u]^e[i].val;
dfs(v,u);
}
}
void build(){
for(R int i = 1;i <= tot;i++){//每个环进行一遍线性基处理
for(R int j = 62;j>=0;j--){
if(!(circle[i]>>j))continue;
if(!p[j]){p[j]=circle[i];break;}
circle[i] ^= p[j];
}
}
}
int main(){
n = read(),m = read();
for(R int i = 1;i <= m;i++){
int x = read(),y = read();
ll z = read();
addedge(x,y,z),addedge(y,x,z);
}
dfs(1,0);
build();
ll ans = dis[n];
for(R int i = 62;i>=0;i--){
if((ans^p[i])>ans)ans ^= p[i];
}
printf("%lld\n",ans);
return 0;
}