[WC2011]最大XOR和路徑
阿新 • • 發佈:2019-02-16
etc pri span tro gis code -- 選擇 include
題目
神仙題啊
發現題目裏有一句非常重要的話“當一條邊在路徑中出現了多次時,其權值在計算 XOR 和時也要被計算相應多的次數”
這告訴我們走一條邊兩次顯然沒有什麽貢獻
所以計算貢獻的應該是那些走了奇數次的邊
我們發現我們可以把一個環上所有的邊都走奇數次遍歷一個環
而兩個環之間如果有路徑連接的話這兩個環的貢獻都可以被算上,而不去計算路徑的貢獻
也就是連接兩個環的路徑走一次,環上的邊走兩次
所以環非常關鍵,我們可以選擇很多的環使得我們的權值異或起來最大
這裏就需要一個線性基了,我們可以配合\(dfs\)搜索樹,遇到一條返祖邊就找到一個環,加入線性基
盡管並沒有加入所有的環,但是這些環可以將所有其他環都表示出來了
之後我們選擇一條從\(1\)到\(n\)的路徑作為初值,從線性基裏選擇一些環來增廣這條路徑,使得異或和最大就好了
代碼
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define maxn 100005 #define re register #define LL long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) inline LL read() { LL x=0;char c=getchar();while(c<‘0‘||c>‘9‘) c=getchar(); while(c>=‘0‘&&c<=‘9‘) x=(x<<3)+(x<<1)+c-48,c=getchar();return x; } struct E{int v,nxt;LL w;}e[maxn<<1]; int head[maxn],dfn[maxn]; LL pre[maxn]; int num,n,m,cnt; LL lb[66]; inline void add(int x,int y,LL z) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;} inline void ins(LL x) { for(re int j=62;j>=0;--j) if(x>>j&1ll) { if(!lb[j]) {lb[j]=x;break;} else x^=lb[j]; } } void tarjan(int x,int fa) { dfn[x]=1; for(re int i=head[x];i;i=e[i].nxt) if(!dfn[e[i].v]) pre[e[i].v]=pre[x]^e[i].w,tarjan(e[i].v,x); else ins(pre[x]^pre[e[i].v]^e[i].w); } int main() { n=read(),m=read(); int x,y;LL z; for(re int i=1;i<=m;i++) x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z); tarjan(1,0); LL ans=pre[n]; for(re int i=62;i>=0;--i) if((ans^lb[i])>ans) ans^=lb[i]; printf("%lld\n",ans); return 0; }
[WC2011]最大XOR和路徑