题意:
给你一张图,每次有2种操作
1 l r 表示从第l条边到第r条边,如果有这条边就删掉,否则就加上
2 x y 表示问与点x直接相连的点集是否与y直接相连的点集相同
题解:
将输入的边编号然后分块,如果要反转的两个区间不在一个块内,那么暴力l块和暴力r块,块间使用flag标记是否翻转。很优秀的想法。
#include<bits/stdc++.h>
using namespace std;
#define ll unsigned long long
const int N=2e5+5,M=505;
ll has[N],val[N],s[M][N];
int flag[M],lef[M],rig[M],blog[N],a[N],b[N];
int main()
{
int t;
scanf("%d",&t);
srand(unsigned(time(NULL)));
for(int i=1;i<N;i++)
has[i]=rand();
while(t--)
{
int n,m,bl;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
val[i]=0;
bl=sqrt(m);
for(int i=1;i<=m;i++)
blog[i]=(i+bl-1)/bl;
for(int i=1;i<=(m+bl-1)/bl;i++)
{
lef[i]=(i-1)*bl+1,rig[i]=min(i*bl,m);
for(int j=1;j<=n;j++)
s[i][j]=0;
flag[i]=0;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i],&b[i]);
s[blog[i]][a[i]]^=has[b[i]];
s[blog[i]][b[i]]^=has[a[i]];
}
int q;
scanf("%d",&q);
while(q--)
{
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op==2)
{
ll s_a=val[x],s_b=val[y];
for(int i=1;i<=(m+bl-1)/bl;i++)
if(!flag[i])
s_a^=s[i][x],s_b^=s[i][y];
printf("%d",s_a==s_b);
}
else
{
if(blog[x]+1<blog[y])
{
for(int i=x;i<=rig[blog[x]];i++)
val[a[i]]^=has[b[i]],val[b[i]]^=has[a[i]];
for(int i=blog[x]+1;i<blog[y];i++)
flag[i]^=1;
for(int i=lef[blog[y]];i<=y;i++)
val[a[i]]^=has[b[i]],val[b[i]]^=has[a[i]];
}
else
{
for(int i=x;i<=y;i++)
val[a[i]]^=has[b[i]],val[b[i]]^=has[a[i]];
}
}
}
printf("\n");
}
return 0;
}