分治+并查集。假设要求[L,mid]的答案,那么很明显,如果一条边的两个端点都>mid的话或者一个端点>mid一个端点<L,说明询问[L,mid]这个区间中任何一点时候,这一条边都是连接的,否则的话递归下去处理。[mid+1,R]同理。
一个图不是二分图的话说明存在奇环,奇环可以用并查集处理。这里的并查集不使用路径压缩而使用按轶合并。并查集的还原操作可以用一个栈记录每次合并时的具体操作,然后按序还原即可。
代码
1 #include<cstdio> 2 #include<vector> 3 #define N 300010 4 using namespace std; 5 int f[N],d[N]; 6 int n,m,i,dp; 7 int tt[N],pre[N],p[N],ans[N],flag[N]; 8 int tot,stack[N],a[N],b[N],g[N]; 9 vector<int> vec[N]; 10 void link(int x,int y) 11 { 12 dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y; 13 } 14 int getfa(int x,int& y) 15 { 16 y=0; 17 while (x!=f[x]) 18 { 19 y^=g[x]; 20 x=f[x]; 21 } 22 return x; 23 } 24 void Union(int x,int y,int &z) 25 { 26 int disx,disy; 27 x=getfa(x,disx); 28 y=getfa(y,disy); 29 if (x!=y) 30 { 31 if (d[x]>d[y]) x^=y^=x^=y; 32 f[x]=y; 33 g[x]=(disx^disy^1); 34 tot++;stack[tot]=x; 35 if (d[x]==d[y]) 36 { 37 flag[tot]=1; 38 d[y]++; 39 } 40 else 41 flag[tot]=0; 42 } 43 else 44 { 45 if (disx^disy^1) 46 z|=1; 47 } 48 } 49 void recover(int x) 50 { 51 while (tot>x) 52 { 53 if (flag[tot]) 54 d[f[stack[tot]]]--; 55 f[stack[tot]]=stack[tot]; 56 g[stack[tot]]=0; 57 tot--; 58 } 59 } 60 void solve(int x,int l,int r,int q) 61 { 62 int i,tmp,len,t,Ans; 63 if (l==r) 64 { 65 ans[l]=1-q; 66 return; 67 } 68 int mid=(l+r)>>1; 69 70 vec[2*x].clear(); 71 vec[2*x+1].clear(); 72 tmp=tot; 73 Ans=q; 74 len=vec[x].size(); 75 for (i=0;i<len;i++) 76 { 77 t=vec[x][i]; 78 if ((a[t]>mid)||((a[t]<l)&&(b[t]>mid))) 79 Union(a[t],b[t],Ans); 80 else 81 vec[2*x].push_back(t); 82 } 83 solve(2*x,l,mid,Ans); 84 85 Ans=q; 86 recover(tmp); 87 for (i=0;i<len;i++) 88 { 89 t=vec[x][i]; 90 if ((b[t]<mid+1)||((a[t]<mid+1)&&(b[t]>r))) 91 Union(a[t],b[t],Ans); 92 else 93 vec[2*x+1].push_back(t); 94 } 95 solve(2*x+1,mid+1,r,Ans); 96 } 97 int main() 98 { 99 int tt; 100 scanf("%d",&tt); 101 while (tt) 102 { 103 tt--; 104 scanf("%d%d",&n,&m); 105 for (i=1;i<=n;i++) 106 { 107 g[i]=0; 108 f[i]=i; 109 } 110 tot=0; 111 vec[1].clear(); 112 for (i=1;i<=m;i++) 113 { 114 scanf("%d%d",&a[i],&b[i]); 115 if (a[i]>b[i]) 116 a[i]^=b[i]^=a[i]^=b[i]; 117 vec[1].push_back(i); 118 } 119 solve(1,1,n,0); 120 for (i=1;i<=n;i++) 121 printf("%d",ans[i]); 122 printf(" "); 123 } 124 }