1. 程式人生 > >【CF938G】Shortest Path Queries(線段樹分治,並查集,線性基)

【CF938G】Shortest Path Queries(線段樹分治,並查集,線性基)

題面

CF
洛谷

題解

吼題啊。
對於每個邊,我們用一個map維護它出現的時間,
發現詢問單點,邊的出現時間是區間,所以線段樹分治。
既然路徑最小值就是異或最小值,並且可以不是簡單路徑,
不難讓人想到WC2011那道最大Xor路徑和。
用一樣的套路,我們動態維護一棵生成樹,碰到一個非樹邊,
就把這個環的異或和丟到線性基裡面去,這樣子直接查就好了。
動態維護生成樹直接用並查集就好了,沒有必要LCT
大概就是永遠不進行路徑壓縮,每次啟發式合併。
詢問的時候暴跳父親。
然後撤銷操作的話,維護一個棧,每次存下當前的修改操作,
撤銷的時候倒序還原就好了。
細節很多,第一次寫這樣的東西,調了好久啊。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
#define MAX 200200
#define ll long long
#define pi pair<int,int>
#define mp(x,y) make_pair(x,y)
#define lson (now<<1) #define rson (now<<1|1) inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct
xxj { int p[31]; void insert(int x) { for(int i=30;~i;--i) if(x&(1<<i)) { if(!p[i]){p[i]=x;break;} x^=p[i]; } } int Query(int x){for(int i=30;~i;--i)x=min(x,x^p[i]);return x;} }G; struct Node{int u,v,w;}p[MAX<<1]; pi q[MAX]; int n,m; map<pi,int> M; vector<Node> seg[MAX<<2]; void Modify(int now,int l,int r,int L,int R,Node e) { if(L>R)return;if(L<=l&&r<=R){seg[now].push_back(e);return;} int mid=(l+r)>>1; if(L<=mid)Modify(lson,l,mid,L,R,e); if(R>mid)Modify(rson,mid+1,r,L,R,e); } int tim,cnt,L[MAX<<1],R[MAX<<1]; int f[MAX],sz[MAX],Xor[MAX]; int getf(int x){while(x!=f[x])x=f[x];return x;} int getxor(int x){int ret=0;while(x!=f[x])ret^=Xor[x],x=f[x];return ret;} void Divide(int now,int l,int r,xxj G) { vector<Node> c;c.clear(); for(int i=0,lim=seg[now].size();i<lim;++i) { int u=seg[now][i].u,v=seg[now][i].v,w=seg[now][i].w; int f1=getf(u),f2=getf(v); if(f1==f2)G.insert(getxor(u)^getxor(v)^w); else { if(sz[f1]>sz[f2])swap(f1,f2),swap(u,v); w^=getxor(v)^getxor(u); c.push_back((Node){f1,f2,sz[f2]}); Xor[f1]=w;f[f1]=f2;sz[f2]+=sz[f1]; } } if(l==r) printf("%d\n",G.Query(getxor(q[l].first)^getxor(q[l].second))); else { int mid=(l+r)>>1; Divide(lson,l,mid,G);Divide(rson,mid+1,r,G); } for(int i=c.size()-1;~i;--i) { int u=c[i].u,v=c[i].v,w=c[i].w; sz[v]=w;f[u]=u;Xor[u]=0; } } int main() { //freopen("938G.in","r",stdin); //freopen("938G.out","w",stdout); n=read();m=read(); for(int i=1;i<=m;++i) { int x=read(),y=read(),w=read(); p[++cnt]=(Node){x,y,w}; L[cnt]=1;M[mp(x,y)]=cnt;R[cnt]=-1; } int Q=read(); for(int i=1;i<=Q;++i) { int opt=read(),x=read(),y=read(); if(x>y)swap(x,y); if(opt==1) { p[++cnt]=(Node){x,y,read()}; L[cnt]=tim+1;R[cnt]=-1;M[mp(x,y)]=cnt; } else if(opt==2)R[M[mp(x,y)]]=tim; else q[++tim]=mp(x,y); } for(int i=1;i<=cnt;++i)if(R[i]==-1)R[i]=tim; for(int i=1;i<=cnt;++i)Modify(1,1,tim,L[i],R[i],p[i]); for(int i=1;i<=n;++i)f[i]=i,sz[i]=1; Divide(1,1,tim,G); return 0; }