codeforces813F Bipartite Checking -- LCT+分治

传送门

题目大意:

给你一个有 n 个顶点的无向图,初始时没有边,有 q 个操作,每个操作加入或删除一条边,要求每次操作后输出这个图是否是二分图。

显然一个图是二分图的充要条件是不存在长度为奇数的环。
对于图中可能出现的每条边,记录它出现的某些区间,然后考虑分治。
Solve(l,r,U) 表示处理 [l,r] 的答案,其中 U 表示出现区间在 [l,r] 内的边的集合。
LCT 维护图的连通,对于出现区间刚好等于 [l,r] 的边 (x,y) ,判断图中 x y 是否连通。如果连通,再求出 x y 的路径长度,如果是偶数,那么加入边 (x,y) 后会出现长度为奇数的环, [l,r] 的答案全是 NO 。如果不连通,将 x y 连上并分治求 [l,mid],[mid+1,r] 。回溯时删除。

代码:

#include
#include
#include
#include
#include
#include
using namespace std;
#define N 100010
struct Node{
    Node(int x=0,int y=0):x(x),y(y){}
    int x,y;
}a[N],q[N];
struct P{
    P(int w=0,int x=0,int y=0):w(w),x(x),y(y){}
    int w,x,y;
}t;
int x,y,i,j,k,n,m,f[N],ch[N][2],s[N],l[N],Q,p[N];
bool b[N],r[N],v[N];
inline bool Get(int x){
    return ch[f[x]][1]==x;
}
inline void Up(int x){
    s[x]=s[ch[x][0]]+s[ch[x][1]]+1;
}
inline void Update_rev(int x){
    r[x]^=1;
    swap(ch[x][0],ch[x][1]);
}
inline void Down(int x){
    if(r[x]){
        Update_rev(ch[x][0]);
        Update_rev(ch[x][1]);
        r[x]=0;
    }
}
inline void Rotate(int x){
    bool d=Get(x);int y=f[x];
    if(b[y])b[x]=1,b[y]=0;else ch[f[y]][Get(y)]=x;
    ch[y][d]=ch[x][d^1];f[ch[y][d]]=y;
    ch[x][d^1]=y;f[x]=f[y];f[y]=x;Up(y);
}
inline void Push(int x){
    if(!b[x])Push(f[x]);
    Down(x);
}
inline void Splay(int x){
    for(Push(x);!b[x];Rotate(x))
    if(!b[f[x]])Rotate(Get(x)==Get(f[x])?f[x]:x);
    Up(x);
}
inline void Access(int x){
    int y=0;
    while(x){
        Splay(x);
        b[ch[x][1]]=1;ch[x][1]=y;b[y]=0;Up(x);
        y=x;x=f[x];
    }
}
inline void mr(int x){
    Access(x);Splay(x);Update_rev(x);
}
inline void Link(int x,int y){
    mr(x);f[x]=y;
}
inline void Del(int x,int y){
    mr(x);Access(y);Splay(y);
    ch[y][0]=f[x]=0;b[x]=1;Up(y);
}
inline int Find(int x){
    if(f[x])return Find(f[x]);
    return x;
}
inline int Query(int x,int y){
    mr(x);Access(y);Splay(y);
    return s[y];
}
map<int,int>M[N];
vector

g; inline void Solve(int l,int r,vector

&g){ vector

L,R; vector<int>c; int Mid=l+r>>1; for(int i=0;iif(g[i].x==l&&g[i].y==r){ if(Find(a[g[i].w].x)!=Find(a[g[i].w].y))Link(a[g[i].w].x,a[g[i].w].y),c.push_back(i);else if(Query(a[g[i].w].x,a[g[i].w].y)&1){ for(int j=l;j<=r;j++)puts("NO"); for(int j=0;jreturn; } }else if(g[i].y<=Mid)L.push_back(g[i]);else if(g[i].x>Mid)R.push_back(g[i]);else L.push_back(P(g[i].w,g[i].x,Mid)),R.push_back(P(g[i].w,Mid+1,g[i].y)); } if(l==r){ puts("YES"); for(int j=0;jreturn; } Solve(l,Mid,L);Solve(Mid+1,r,R); for(int j=0;jint main(){ scanf("%d%d",&n,&Q); for(i=1;i<=n;i++)b[i]=s[i]=1; for(i=1;i<=Q;i++){ scanf("%d%d",&q[i].x,&q[i].y); if(q[i].x>q[i].y)swap(q[i].x,q[i].y); if(!M[q[i].x][q[i].y])M[q[i].x][q[i].y]=++m,a[m]=Node(q[i].x,q[i].y); } for(i=1;i<=Q;i++){ x=M[q[i].x][q[i].y]; if(p[x])g.push_back(P(x,p[x],i-1)),p[x]=0;else p[x]=i; } for(i=1;i<=m;i++)if(p[i])g.push_back(P(i,p[i],Q)); Solve(1,Q,g); return 0; }

你可能感兴趣的:(LCT,分治,codeforces)