CF938G Shortest Path Queries
作者:互联网
Shortest Path Queries
给出一个连通带权无向图,边有边权,要求支持 q 个操作:
- x y d 在原图中加入一条 x 到 y 权值为 d 的边
- x y 把图中 x 到 y 的边删掉
- x y 表示询问 x 到 y 的异或最短路
保证任意操作后原图连通无重边自环且操作均合法
n,m,q≤200000
题解
与WC2011 最大XOR和路径一样,先考虑没有加边删边的做法
- 做出原图的任意一棵生成树
- 把每个非树边和树边形成的环丢进线性基里
- 询问时把两点在树上的路径异或和丢进线性基里求最小异或和
有加边删边呢?线段树分治即可。
每到一个点,把边都连上,然后分治左右。退出时撤销即可。
需要用到按秩合并并查集以支持快速查询和撤销操作。并查集在合并两个点时,将儿子节点压入栈,撤销时直接把儿子节点的贡献删除即可。
#include<bits/stdc++.h>
using namespace std;
template<class T> T read(){
T x=0,w=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template<class T> T read(T&x){
return x=read<T>();
}
#define co const
#define il inline
typedef long long LL;
co int N=200000+10;
struct edge {int u,v,w,l,r;}e[N<<1];
vector<edge> g[N<<2];
map<pair<int,int>,int> mp;
int val[N],fa[N],siz[N];
int stk[N<<1],top;
#define lc (x<<1)
#define rc (x<<1|1)
void update(int x,int l,int r,co edge&e){
if(e.l>e.r) return; // edit 1
if(e.l<=l&&r<=e.r)
return g[x].push_back(e);
int mid=(l+r)>>1;
if(e.l<=mid) update(lc,l,mid,e);
if(e.r>mid) update(rc,mid+1,r,e);
}
struct ask {int u,v;}qst[N];
int bas[20][30];
int find_fa(int x){
return fa[x]==x?x:find_fa(fa[x]);
}
int find_val(int x){
return fa[x]==x?0:val[x]^find_val(fa[x]);
}
void insert(int x,int dep){
for(int i=0;i<(int)g[x].size();++i){
int u=g[x][i].u,v=g[x][i].v,w=g[x][i].w;
int fu=find_fa(u),fv=find_fa(v);
if(fu!=fv){
if(siz[fu]>siz[fv]) swap(fu,fv),swap(u,v);
fa[fu]=fv,siz[fv]+=siz[fu],val[fu]=find_val(u)^find_val(v)^w;
stk[++top]=fu;
}
else{
w^=find_val(u)^find_val(v);
for(int j=29;j>=0;--j)if(w>>j&1){
if(!bas[dep][j]) {bas[dep][j]=w;break;}
w^=bas[dep][j];
}
}
}
}
void reset(int to){
for(;top>to;--top){
int u=stk[top];
siz[fa[u]]-=siz[u],val[u]=0,fa[u]=u;
}
}
void solve(int x,int l,int r,int dep){
int tmp=top;
insert(x,dep);
if(l==r){
int u=qst[l].u,v=qst[l].v;
int ans=find_val(u)^find_val(v);
for(int i=29;i>=0;--i)if(ans>>i&1)
if(bas[dep][i]) ans^=bas[dep][i];
printf("%d\n",ans);
return reset(tmp);
}
int mid=(l+r)>>1;
copy(bas[dep],bas[dep]+30,bas[dep+1]),solve(lc,l,mid,dep+1);
copy(bas[dep],bas[dep]+30,bas[dep+1]),solve(rc,mid+1,r,dep+1);
reset(tmp);
}
int main(){
int n=read<int>(),m=read<int>();
int ecnt=0;
for(int i=1;i<=m;++i){
int u=read<int>(),v=read<int>(),w=read<int>();
e[++ecnt]=(edge){u,v,w,1,-1},mp[make_pair(u,v)]=ecnt;
}
int q=read<int>();
int totq=0;
for(int i=1;i<=q;++i){
int opt=read<int>();
if(opt==1){ // add
int x=read<int>(),y=read<int>(),d=read<int>();
e[++ecnt]=(edge){x,y,d,totq+1,-1},mp[make_pair(x,y)]=ecnt;
}
else if(opt==2){ // remove
int x=read<int>(),y=read<int>();
e[mp[make_pair(x,y)]].r=totq,mp[make_pair(x,y)]=0;
}
else{ // calculate
int x=read<int>(),y=read<int>();
qst[++totq]=(ask){x,y};
}
}
for(int i=1;i<=ecnt;++i){
if(e[i].r==-1) e[i].r=totq;
update(1,1,totq,e[i]);
}
for(int i=1;i<=n;++i) fa[i]=i,siz[i]=1;
solve(1,1,totq,0);
return 0;
}
我写的线段树是需要判断插入合不合法的,好几次因为这个RE了。
标签:bas,val,int,dep,read,Shortest,Path,find,CF938G 来源: https://www.cnblogs.com/autoint/p/11495714.html