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

Zhang_RQ

2018-03-17 09:35:37

Solution

~~(贴一下[博客](https://zhang-rq.github.io/2018/03/17/BZOJ2115-WC2011-Xor/))~~ ### 题目大意 你有一张$\text{N}$个点$\text{M}$条边的无向图,每条边上都有权值,现在请你求出来一条路径,使得这条路径上所有边权的异或和最大。 ### 题解 **前置技能:线性基** (不会的戳这里[线性基学习笔记](https://zhang-rq.github.io/2018/03/17/%E7%BA%BF%E6%80%A7%E5%9F%BA%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/)) 我们可以发现,这张图上会出现很多的环,而如果走一个环,就会**只**获得这个环的异或和。因为在非环路都走了两遍,所以我们就可以将所有环都求出来,然后随意找一条从$1$到$N$的路径,并使用线性基贪心地选,这样就可以选出最大的路径了。 ```cpp #include<cstdio> #include<cstring> #include<cstdlib> #include<cctype> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<set> #include<map> #include<queue> #include<stack> typedef long long ll; typedef unsigned long long ull; using namespace std; const int MAXN=1E5+5; const int MAXM=2E5+5; struct node{ int nxt,v; ll w; }Edge[MAXM]; int n,m,u,v; ll w; int head[MAXN],cnt_e,cnt; ll dis[MAXN],lop[MAXM],b[64]; bool vis[MAXN]; inline void add(int u,int v,ll w) { Edge[++cnt_e].v=v; Edge[cnt_e].nxt=head[u]; Edge[cnt_e].w=w; head[u]=cnt_e; } void dfs(int x,int fa) { vis[x]=1; for(int i=head[x];i;i=Edge[i].nxt) { int v=Edge[i].v; if(v==fa) continue; if(vis[v]) {lop[++cnt]=dis[x]^dis[v]^Edge[i].w;continue;} dis[v]=dis[x]^Edge[i].w; dfs(v,x); } } void build() { for(int i=1;i<=cnt;i++) for(int j=62;~j;j--) if(lop[i]>>j&1) { if(b[j]) lop[i]^=b[j]; else { b[j]=lop[i]; for(int k=j-1;k>=1;k--) if(b[k]&&b[j]>>k&1) b[j]^=b[k]; for(int k=j+1;k<=62;k++) if(b[k]>>j&1) b[k]^=b[j]; break; } } } ll solve(ll s) { ll ret=s; for(int i=62;~i;i--) if((ret^b[i])>ret) ret^=b[i]; return ret; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d%lld",&u,&v,&w); add(u,v,w);add(v,u,w); } dfs(1,0); build(); printf("%lld\n",solve(dis[n])); } ```