description
一張無向圖,支持如下三種操作:
$1 \ x \ y \ d \ $ :加一條連接\(x,y\),邊權為\(d\)的邊。
$2 \ x \ y \(:刪除\)x,y$之間的邊。
$3 \ x \ y \(:查詢\)x\(到\)y\(的異或最短路,也就是異或和最小的一條路徑。 保證任意時刻圖中無重邊無自環,**且圖連通**。 \)n,m,q \le 200000$
sol
根據WC2011最大XOR和路徑那題的理論,圖中兩點的異或路徑一定是這兩點在某棵生成樹上的路徑異或和再異或上若干個環的異或和。
這題保證圖連通,所以這個性質是成立的。
我們考慮動態維護圖的連通性。運用線段樹分治,以詢問為下標建線段樹,把每條邊放在線段樹對應的\(\log\)個節點上,最終\(dfs\)整棵線段樹計算答案。
在\(dfs\)的過程中我們需要支持的是維護連通性以及維護路徑異或和。
對於一條邊\((u,v,w)\),如果\(u,v\)已經連通,那么就可以往線性基里插入\(u,v\)的路徑異或和異或上\(w\)的值。否則需要按秩合並\(u,v\)所在的並查集,同時還需要維護路徑異或和。我們對每個點記它到它所在並查集的根的路徑異或和,那么每次合並的時候相當於要給其中一個連通塊整體異或上一個數。打標記即可。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
#define pi pair<int,int>
#define mk make_pair
const int N = 2e5+5;
struct edge{int u,v,w,l,r;}E[N<<1];
struct query{int u,v;}q[N];
struct mdf{int x,y,sz;}s[N<<1];
int n,m,tot,fa[N],sz[N],tag[N],top;
vector<int>v[N<<2];
map<pi,int>M;
struct xxj{
int p[31];
void insert(int x){
for (int j=30;~j;--j)
if ((x>>j)&1){
if (!p[j]) {p[j]=x;return;}
x^=p[j];
}
}
int calc(int x){
for (int j=30;~j;--j)
x=min(x,x^p[j]);
return x;
}
}tmp;
void modify(int x,int l,int r,int ql,int qr,int i){
if (l>=ql&&r<=qr) {v[x].push_back(i);return;}
int mid=l+r>>1;
if (ql<=mid) modify(x<<1,l,mid,ql,qr,i);
if (qr>mid) modify(x<<1|1,mid+1,r,ql,qr,i);
}
int getf(int x){
while (x!=fa[x]) x=fa[x];
return x;
}
int getd(int x){
int d=0;
while (x!=fa[x]) d^=tag[x],x=fa[x];
return d;
}
void dfs(int x,int l,int r,xxj S){
int tt=top;
for (auto i:v[x]){
int x=getf(E[i].u),y=getf(E[i].v),dx=getd(E[i].u),dy=getd(E[i].v);
if (x==y) {S.insert(dx^dy^E[i].w);continue;}
if (sz[x]>sz[y]) swap(x,y),swap(dx,dy);
s[++top]=(mdf){x,y,sz[y]};
fa[x]=y;sz[y]+=sz[x];tag[x]=dx^dy^E[i].w;
}
if (l==r){
int dx=getd(q[l].u),dy=getd(q[l].v);
printf("%d\n",S.calc(dx^dy));
}else{
int mid=l+r>>1;
dfs(x<<1,l,mid,S);dfs(x<<1|1,mid+1,r,S);
}
while (top>tt){
int x=s[top].x,y=s[top].y;
tag[x]=0;fa[x]=x;sz[y]=s[top].sz;--top;
}
}
int main(){
n=gi();m=gi();
for (int i=1;i<=m;++i){
int u=gi(),v=gi(),w=gi();if (u>v) swap(u,v);
E[i]=(edge){u,v,w,1,-1};M[mk(u,v)]=i;
}
int Case=gi();while (Case--){
int op=gi();
if (op==1){
int u=gi(),v=gi(),w=gi();if (u>v) swap(u,v);
E[++m]=(edge){u,v,w,tot+1,-1};M[mk(u,v)]=m;
}else if (op==2){
int u=gi(),v=gi();if (u>v) swap(u,v);
E[M[mk(u,v)]].r=tot;M.erase(mk(u,v));
}else{
int u=gi(),v=gi();
q[++tot]=(query){u,v};
}
}
for (int i=1;i<=m;++i){
if (E[i].r==-1) E[i].r=tot;
if (E[i].l<=E[i].r) modify(1,1,tot,E[i].l,E[i].r,i);
}
for (int i=1;i<=n;++i) fa[i]=i,sz[i]=1;
dfs(1,1,tot,tmp);return 0;
}