给你一幅n个点,m条边的无向图,每条边有权值d,现在有q次操作,有三种操作。
1,给出x,y,d,加入连接x,y的权值为d的边
2,给出x,y,删除这条边
3,给出x,y,问从x到y的路径的最小异或和。
保证操作合法且一直为简单连通图
n,m,q<=1e5
部分分:q=1,且为操作3
考虑部分分。
随便搞一个dfs树出来,你一条返祖边代表一个环。x到y的树路径的xor和为x到根的xor和y到根xor的异或和。考虑让环也有贡献,直接搞个环的线性基即可。
操作这么多?
考虑把每条边的存在时间找出来,然后插到以时间为下标线段树的对应节点,发现一条边最多拆成log条。询问就打在线段树叶子上。
dfs一边线段树区间。我们现在想要维护部分分的两个东西,连通性和简单路径xor和用可撤销并查集做,进来区间的时候按秩合并并记录原来的形态,出去的时候撤销即可。线性基由于很小,直接暴力下传。
一条边按秩合并时间复杂度O(logn),一条原来的边拆成了O(logn)条,时间复杂度O(nlog^2 n)
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef double db;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a
const int N=8e5+5,mo=998244353,M=4e6+5,xs=1331;
struct edge
{
int x,y,z,t;
}dl[N];
bool operator <(edge a,edge b)
{
if (a.x!=b.x) return a.xx ;
if (a.y!=b.y) return a.yy;
if (a.z!=b.z) return a.zreturn a.t tr;
multiset :: iterator it;
int tt,b[M],c[M],val[M],nxt[M],fst[N];
void cr(int x,int y,int z,int t)
{
tt++;
b[tt]=y;
c[tt]=z;
val[tt]=t;
nxt[tt]=fst[x];
fst[x]=tt;
}
int X,Y,Z;
void change(int x,int l,int r,int i,int j)
{
if (l==i&&r==j)
{
cr(x,X,Y,Z);
return ;
}
int m=l+r>>1;
if (j<=m) change(x*2,l,m,i,j);
else if (mx*2+1,m+1,r,i,j);
else
{
change(x*2,l,m,i,m);
change(x*2+1,m+1,r,m+1,j);
}
}
int base[N*4][30];
void ins(int *a,int v)
{
int i;
fd(i,29,0)
if (v&(1<if (!a[i])
{
a[i]=v;
return ;
}
v^=a[i];
}
}
int calc(int *a,int v)
{
int i;
fd(i,29,0)
if (v&(1<return v;
}
int td,p,qx[N],qy[N],prt[N],n,m,i,x,y,z,q,ka;
int rk[N],fa[N],Xor[N];
int get(int x,int &v)
{
if (fa[x]==x) return x;
v^=Xor[x];
return get(fa[x],v);
}
void solve(int ax,int l,int r)
{
int tp=td,x,y,z,rx,ry,v1,v2,i;
for (p=fst[ax];p;p=nxt[p])
{
x=b[p];y=c[p];z=val[p];v1=0;v2=0;
rx=get(x,v1);ry=get(y,v2);
if (rx==ry)
ins(base[ax],z^v1^v2);
else
{
if (rk[rx]>rk[ry]) swap(x,y),swap(rx,ry);
dl[++td]={rx,Xor[rx],rk[rx],fa[rx]};
dl[++td]={ry,Xor[ry],rk[ry],fa[ry]};
fa[rx]=ry;
Xor[rx]=v1^v2^z;
if (rk[rx]==rk[ry]) rk[ry]++;
}
}
if (l==r&&qx[l])
{
x=qx[l];y=qy[l];
v1=v2=0;
get(x,v1);get(y,v2);
prt[l]=calc(base[ax],v1^v2);
}
if (l!=r)
{
fo(i,0,29) base[ax*2][i]=base[ax*2+1][i]=base[ax][i];
int m=l+r>>1;
solve(ax*2,l,m);
solve(ax*2+1,m+1,r);
}
while (td>tp)
{
x=dl[td].x;
Xor[x]=dl[td].y;
rk[x]=dl[td].z;
fa[x]=dl[td].t;
td--;
}
}
int main()
{
freopen("t4.in","r",stdin);
freopen("t4.out","w",stdout);
scanf("%d %d",&n,&m);
fo(i,1,m)
{
scanf("%d %d %d",&x,&y,&z);
if (x>y) swap(x,y);
tr.insert({x,y,z,1});
}
fo(i,1,n) fa[i]=i;
scanf("%d",&q);
fo(i,1,q)
{
scanf("%d %d %d",&ka,&x,&y);
if (x>y) swap(x,y);
if (ka==1)
{
scanf("%d",&z);
tr.insert({x,y,z,i});
}else
if (ka==2)
{
it=tr.lower_bound({x,y,0,0});
X=x;Y=y;Z=(*it).z;
change(1,1,q,(*it).t,i);
tr.erase(it);
}else
{
qx[i]=x;qy[i]=y;
}
}
while (!tr.empty())
{
it=tr.begin();
X=(*it).x;Y=(*it).y;Z=(*it).z;
change(1,1,q,(*it).t,q);
tr.erase(it);
}
solve(1,1,q);
fo(i,1,q) if (qx[i])
{
printf("%d\n",prt[i]);
}
}