zoukankan      html  css  js  c++  java
  • 【xsy2506】 bipartite 并查集+线段树

    题目大意:有$n$个点,你需要操作$m$次。每次操作为加入/删除一条边。

    问你每次操作后,这$n$个点构成的图是否是二分图。

    数据范围:$n,m≤10^5$。

    此题并没有强制在线,考虑离线做法。

    一条边在某个时间被加入,然后又被删除。

    设这条边出现的时间为$[l,r]$,我们开一棵线段树,在对应的区间上标记出这一条线段。

    最后我们遍历整个线段树,把这些线段往并查集上加,同时维护当前点的颜色,然后简单判断下就没了。

    这个并查集需要支持撤销操作,所以不能路径压缩,需要按秩合并

    时间复杂度:$O(nlog^2 n)$。

     1 #include<bits/stdc++.h>
     2 #define M 100005
     3 #define mid ((a[x].l+a[x].r)>>1)
     4 using namespace std;
     5 
     6 int f[M]={0},siz[M]={0},val[M]={0}; int get(int x){return x==f[x]?x:get(f[x]);}
     7 int getdis(int x){return x==f[x]?0:val[x]+getdis(f[x]);}
     8 int n,m,ok=1;
     9 map<int,int> mp[M];
    10 
    11 struct seg{
    12     int l,r; vector<int> u,v,F;
    13     void add(){
    14         int S=u.size();
    15         for(int i=0;i<S;i++){
    16             int U=get(u[i]),V=get(v[i]);
    17             if(U==V){
    18                 if((getdis(u[i])+getdis(v[i]))%2==0) ok=0;
    19                 F.push_back(-1); continue;
    20             }
    21             if(siz[U]<siz[V]){swap(U,V); swap(u[i],v[i]);}
    22             int d=getdis(u[i])+getdis(v[i]);
    23             F.push_back(V); f[V]=U; val[V]=(d+1)&1; siz[U]+=siz[V];
    24         }
    25     }
    26     void del(){
    27         int S=u.size();
    28         for(int i=S-1;~i;i--){
    29             if(F[i]==-1) continue;
    30             int U=get(u[i]),V=F[i];
    31             siz[U]-=siz[V];
    32             f[V]=V; val[V]=0;
    33         }
    34     }
    35             
    36 }a[M<<2]={0};
    37 
    38 void build(int x,int l,int r){
    39     a[x].l=l; a[x].r=r; if(l==r) return;
    40     build(x<<1,l,mid); build(x<<1|1,mid+1,r);
    41 }
    42 void updata(int x,int l,int r,int U,int V){
    43     if(l<=a[x].l&&a[x].r<=r){a[x].u.push_back(U); a[x].v.push_back(V);return;}
    44     if(l<=mid) updata(x<<1,l,r,U,V);
    45     if(mid<r) updata(x<<1|1,l,r,U,V);
    46 }
    47 
    48 int solve(int x){
    49     int lastok=ok;
    50     a[x].add();
    51     if(ok==0) for(int i=a[x].l;i<=a[x].r;i++) printf("NO
    ");
    52     else if(a[x].l==a[x].r) printf("YES
    ");
    53     else solve(x<<1),solve(x<<1|1);
    54     a[x].del();
    55     ok=lastok;
    56 }
    57 
    58 int main(){
    59     scanf("%d%d",&n,&m);
    60     build(1,1,m);
    61     for(int i=1;i<=n;i++) f[i]=i,siz[i]=1;
    62     for(int i=1;i<=m;i++){
    63         int u,v; scanf("%d%d",&u,&v);
    64         if(u<v) swap(u,v);
    65         if(mp[u][v]){
    66             updata(1,mp[u][v],i-1,u,v);
    67             mp[u][v]=0;
    68         }else mp[u][v]=i;
    69     }
    70     for(int i=1;i<=n;i++){
    71         for(map<int,int>::iterator it=mp[i].begin();it!=mp[i].end();it++)
    72         if(it->second)
    73         updata(1,it->second,m,i,it->first);
    74     }
    75     solve(1);
    76 }
  • 相关阅读:
    mysqllog
    清理:db上面的过期的binlog,释放磁盘空间。 (转)
    linux下shell命令trap
    mvc
    uci随笔
    luci 随笔
    shell脚本 整数比较
    lua学习
    OPENWRT make menuconfig错误之一
    openwrt 中make的使用
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10556559.html
Copyright © 2011-2022 走看看