zoukankan      html  css  js  c++  java
  • [HDU5354]Bipartite Graph(CDQ分治+并查集)

    经典动态二分图问题。

    考虑solve(l,r)分治成l,mid和mid+1,r。先将区间[mid+1,r]中的点全部加入图中,若此时存在奇环则ans[l..mid]全部为0,否则递归到左边。

    递归完左边后将右边的点全部删去,左边点全部加入,按同样的方法处理右边。

    判断奇环使用可撤销带权并查集,注意多组数据不要用memset。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=200010;
     8 int T,n,m,top,cnt,u,v;
     9 int fa[N],sz[N],d[N],ans[N],h[N],nxt[N],to[N];
    10 struct P{ int a,b,c; }s[3*N];
    11 struct S{ int x,y; };
    12 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    13 
    14 void init(){ cnt=0; rep(i,1,n) fa[i]=i,sz[i]=1,d[i]=0,h[i]=0; }
    15 
    16 S get(int x){
    17     if (fa[x]==x) return (S){x,0};
    18     S t=get(fa[x]); return (S){t.x,t.y^d[x]};
    19 }
    20 
    21 void uni(int x,int y){
    22     int t1=get(x).y; x=get(x).x;
    23     int t2=get(y).y; y=get(y).x;
    24     if (sz[x]<sz[y]) swap(x,y);
    25     s[++top]=(P){0,y,y}; s[++top]=(P){1,x,sz[x]}; s[++top]=(P){2,y,0};
    26     fa[y]=x; d[y]=t1^t2^1; sz[x]+=sz[y];
    27 }
    28 
    29 void cancel(int x){
    30     if (s[x].a==0) fa[s[x].b]=s[x].c;
    31     if (s[x].a==1) sz[s[x].b]=s[x].c;
    32     if (s[x].a==2) d[s[x].b]=s[x].c;
    33 }
    34 
    35 void solve(int l,int r){
    36     if (l==r) { ans[l]=1; return; }
    37     int mid=(l+r)>>1,tmp=top; bool flag=0;
    38     rep(u,mid+1,r)
    39         for (int i=h[u]; i; i=nxt[i]){
    40             int v=to[i];
    41             if (v>=l && v<=mid) continue;
    42             if (get(u).x!=get(v).x) uni(u,v);
    43             else if (get(u).y==get(v).y) { flag=1; break; }
    44         }
    45     if (flag) rep(i,l,mid) ans[i]=0; else solve(l,mid);
    46     while (top>tmp) cancel(top--); flag=0;
    47     rep(u,l,mid)
    48         for (int i=h[u]; i; i=nxt[i]){
    49             int v=to[i];
    50             if (v>mid && v<=r) continue;
    51             if (get(u).x!=get(v).x) uni(u,v);
    52             else if (get(u).y==get(v).y) { flag=1; break; }
    53         }
    54     if (flag) rep(i,mid+1,r) ans[i]=0; else solve(mid+1,r);
    55     while (top>tmp) cancel(top--);
    56 }
    57 
    58 int main(){
    59     freopen("hdu5354.in","r",stdin);
    60     freopen("hdu5354.out","w",stdout);
    61     for (scanf("%d",&T); T--; ){
    62         scanf("%d%d",&n,&m); init();
    63         rep(i,1,m) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    64         solve(1,n);
    65         rep(i,1,n) printf("%d",ans[i]); puts("");
    66     }
    67     return 0;
    68 }
  • 相关阅读:
    数据库基础知识复习-2013.09.24
    2013.9.24 答题
    使用单向循环链表实现约瑟夫问题
    C++关于数字逆序输出的两种思路,及字符串逆序输出
    题目要求:建立一个类Str,将一个正整数转换成相应的字符串,例如整数3456转换为字符串"3456".
    将博客搬至CSDN
    Android 下载模块分析(DownloadManager和DownloadProvider)
    linux shell基础语法
    Android过滤Logcat输出
    (Java 多线程系列)Java 线程池(Executor)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9858063.html
Copyright © 2011-2022 走看看