Codeforces 938G Shortest Path Queries 线段树分治+并查集+线性基
2018-03-04 21:37
330 查看
题意
给出一个连通带权无向图,边有边权,要求资瓷q个操作:1 x y d在原图中加入一条x到y权值为b的边
2 x y把图中x到y的边删掉
3 x y表示询问x到y的异或最短路
保证任意操作后原图连通无重边自环且操作均合法
n,m,q<=200000
分析
如果没有前两个操作的话,我们就可以把原图的dfs树建出来,那么x到y的异或最短路就是它们在dfs树上的路径再异或上任意个由返祖边组成的环。这个显然可以用线性基来维护。现在有了加边和删边,那么我们可以用线段树分治来做,把每条边放到O(log)个区间上,然后分治。
设f[x]表示dfs树上x到根的路径异或和,可以通过按秩合并并查集来维护f[x],然后每次退栈的时候撤销即可。
每个分治节点维护一个线性基,每次把线性基复制一遍传给下一层即可。
一开始wa了是因为在并查集合并的时候,并查集上新增那条边的权值应该是f[x] xor f[y] xor 图中新增边的权值,而我少加了一个f[x]。关键是我少加了居然还能过对拍。
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<map> #include<vector> #define pb(x) push_back(x) #define mp(x,y) make_pair(x,y) using namespace std; const int N=200005; typedef pair<int,int> pi; int n,m,val ,f ,size ,stack ,top,bas[35][35],bin[35],cnt,tot; pi qu ; struct edge{int u,v,w,s,t;}e[N*2]; map<pi,int> ma; vector<int> vec[N*4]; int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int find(int x) { while (f[x]!=x) x=f[x]; return x; } int get_val(int x) { int w=0; while (f[x]!=x) w^=val[x],x=f[x]; return w; } void add(int d,int dep) { for (int i=0;i<vec[d].size();i++) { int id=vec[d][i],u=e[id].u,v=e[id].v,x=find(u),y=find(v); if (x!=y) { if (size[x]>size[y]) swap(u,v),swap(x,y); f[x]=y;size[y]+=size[x];val[x]=get_val(u)^get_val(v)^e[id].w;stack[++top]=x; } else { int w=get_val(u)^get_val(v)^e[id].w; for (int i=30;i>=0;i--) if (w&bin[i]) { if (!bas[dep][i]) {bas[dep][i]=w;break;} else w^=bas[dep][i]; } } } } void del(int tmp) { while (top>tmp) { int x=stack[top];top--; size[f[x]]-=size[x];f[x]=x;val[x]=0; } } void ins(int d,int l,int r,int x,int y,int id) { if (x>y) return; if (l==x&&r==y) {vec[d].pb(id);return;} int mid=(l+r)/2; if (y<=mid) ins(d*2,l,mid,x,y,id); else if (x>mid) ins(d*2+1,mid+1,r,x,y,id); else ins(d*2,l,mid,x,mid,id),ins(d*2+1,mid+1,r,mid+1,y,id); } void solve(int d,int l,int r,int dep) { int tmp=top;add(d,dep); if (l==r) { int x=qu[l].first,y=qu[l].second,w=get_val(x)^get_val(y); for (int i=30;i>=0;i--) if ((w^bas[dep][i])<w) w^=bas[dep][i]; printf("%d\n",w);del(tmp); return; } int mid=(l+r)/2; for (int i=0;i<=30;i++) bas[dep+1][i]=bas[dep][i]; solve(d*2,l,mid,dep+1); for (int i=0;i<=30;i++) bas[dep+1][i]=bas[dep][i]; solve(d*2+1,mid+1,r,dep+1); del(tmp); } int main() { bin[0]=1; for (int i=1;i<=30;i++) bin[i]=bin[i-1]*2; n=read();m=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(),z=read(); e[++cnt].u=x;e[cnt].v=y;e[cnt].w=z; ma[mp(x,y)]=cnt;e[cnt].s=1;e[cnt].t=-1; } int q=read(); for (int i=1;i<=q;i++) { int op=read(),x=read(),y=read(); if (op==1) { int d=read(); e[++cnt].u=x;e[cnt].v=y;e[cnt].w=d; ma[mp(x,y)]=cnt;e[cnt].s=tot+1;e[cnt].t=-1; } else if (op==2) e[ma[mp(x,y)]].t=tot,ma[mp(x,y)]=0; else qu[++tot]=mp(x,y); } for (int i=1;i<=cnt;i++) ins(1,1,tot,e[i].s,e[i].t==-1?tot:e[i].t,i); for (int i=1;i<=n;i++) f[i]=i,size[i]=1; solve(1,1,tot,0); return 0; }
相关文章推荐
- CodeForces 895 C.Square Subsets(状压DP+线性基)
- codeforces 895C Square Subsets 线性基 或 状压DP
- [数位DP][线性基]Codeforces 388D. Fox and Perfect Sets
- CodeForces 724 G.Xor-matic Number of the Graph(组合数学+dfs+线性基)
- CodeForces 587E Duff as a Queen (线段树+线性基)
- codeforces 191 E (树状数组+二分)
- CodeForces 546A A Contest #1(A. Soldier and Bananas)
- Codeforces 612C: Replace To Make Regular Bracket Sequence(栈)
- BZOJ 3569 DZY Loves Chinese II ——线性基
- codeforces 37A Towers
- Codeforces 902 A.Visiting a Friend 贪心
- codeforces_330c
- CodeForces 373B——模拟——Making Sequences is Fun
- codeforces 96B Lucky Numbers (全排列)
- 【BZOJ 4269】再见Xor 线性基
- CodeForces 520 B.Two Buttons(bfs)
- 【数位DP】 【CodeForces 55D】
- codeforces 553 D Nudist Beach
- Codeforces 439C Devu and Partitioning of the Array
- CodeForces 762F. Tree nesting