2019牛客暑期多校训练营(第三场)A.Graph Games (分块)
题意:给你n个点 m条边的一张图 现在有q次操作 每次操作可以选择反转l~r的边号 也可以询问S(l)和S(r) 连接成的点集是否相同
思路:我们把m条边分块 用一个S数组维护每块对一个点的贡献 然后块间打标记 两端暴力
#include <bits/stdc++.h> using namespace std; const double pi = acos(-1.0); const int N = 2e5+7,M = 505; const int inf = 0x3f3f3f3f; const double eps = 1e-6; typedef unsigned long long ll; const ll mod = 1e7+9; int L[M],R[M],block[N],lazy[M]; ll Hash[N],val[N],S[M][N]; int a[N],b[N]; int n,m; int main(){ // ios::sync_with_stdio(false); // cin.tie(0); cout.tie(0); int T; scanf("%d",&T); srand(unsigned(time(NULL))); for(int i=0;i<N;i++) Hash[i]=rand(); while(T--){ scanf("%d%d",&n,&m); int t=sqrt(m); for(int i=1;i<=m;i++){ block[i]=(i+t-1)/t; } for(int i=1;i<=(m+t-1)/t;i++){ L[i]=(i-1)*t+1; R[i]=min(m,i*t); for(int j=1;j<=n;j++) S[i][j]=0; lazy[i]=0; } for(int i=1;i<=m;i++){ scanf("%d%d",&a[i],&b[i]);; S[block[i]][a[i]]^=Hash[b[i]]; S[block[i]][b[i]]^=Hash[a[i]]; } int qq; scanf("%d",&qq); for(int i=1;i<=qq;i++){ int op,l,r; scanf("%d",&op); if(op==1){ scanf("%d%d",&l,&r); int p=block[l]; int q=block[r]; if(p==q){ for(int i=l;i<=r;i++) val[a[i]]^=Hash[b[i]],val[b[i]]^=Hash[a[i]]; }else{ for(int i=1;i<=R[p];i++) val[a[i]]^=Hash[b[i]],val[b[i]]^=Hash[a[i]]; for(int i=p+1;i<=q-1;i++) lazy[i]^=1; for(int i=L[q];i<=r;i++) val[a[i]]^=Hash[b[i]],val[b[i]]^=Hash[a[i]]; } }else{ scanf("%d%d",&l,&r); ll sa=val[l]; ll sb=val[r]; for(int i=1;i<=(m+t-1)/t;i++) if(!lazy[i]) sa^=S[i][l],sb^=S[i][r]; printf("%d",(sa==sb)); } } puts(""); } }