LOJ#121. 「离线可过」动态图连通性

LOJ#121. 「离线可过」动态图连通性

题目描述

这是一道被离线爆艹的模板题。

你要维护一张无向简单图。你被要求加入删除一条边及查询两个点是否连通。

  • 0:加入一条边。保证它不存在。
  • 1:删除一条边。保证它存在。
  • 2:查询两个点是否联通。

输入格式

输入的第一行是两个数 N MN\ MN M。N≤5000,M≤500000N \leq 5000,M \leq 500000N5000,M500000。

接下来 MMM 行,每一行三个数 op x y\text{op} \ x \ yop x y。op\text{op}op 表示操作编号。

输出格式

对于每一个 op=2\text{op}=2op=2 的询问,输出一行 Y 或 N ,表示两个节点是否连通。

样例

样例输入 1

200 5
2 123 127
0 123 127
2 123 127
1 127 123
2 123 127

样例输出 1

N
Y
N

样例输入 2

4 10
0 1 2
0 2 3
0 3 1
2 1 4
0 4 3
2 1 4
1 2 3
2 1 4
1 1 3
2 1 4

样例输出 2

N
Y
Y
N

数据范围与提示

对于数据点 1,N≤200,M≤200

对于数据点 2,N=5,M≤30

对于数据点 3,N=10,M≤1000,其中查询的次数 ≥900 次。

对于数据点 4,N=300,M≤50000

对于数据点 5,N=5000,M≤200000,没有操作 1,其中约 70% 是操作 2。

对于数据点 6,N=5000,M≤200000,没有操作 1,其中约 70% 是操作 0。

对于数据点 7、8,N=100,M≤500000

对于数据点 9,N=5000,M≤500000,图是一棵树,其直径 ≤6

对于数据点 10, N=5000,M≤500000,图是一棵树,其每个点度数 ≤4  。

P.S. 其实 9 是菊花,10 是单链,而没有放随机树的点...

题解Here!

由于BZOJ 上找不到这题,于是拿出了LOJ。。。

话说LOJ和洛谷的评测姬一样吼呢!

这题乍一看,可持久化并查集,然而并不会。。。

但是离线,于是——去吧LCT!

预处理每一条边被删除的时间,动态维护最小生成树。

然后就是基本操作了。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#define MAXN 10010
#define MAXM 1000010
#define MAX (1<<30)
using namespace std;
map<int,int> add_time[MAXN];
int n,m,top=0;
int val[MAXM];
struct Graph{
    int u,v,w;
}a[MAXM];
struct Question{
    int id,f,x,y;
}que[MAXM];
inline int read(){
    int date=0,w=1;char c=0,last=0;
    while(c<'0'||c>'9'){last=c;c=getchar();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    if(last=='-')w=-1;
    return date*w;
}
namespace LCT{
    int top=0,stack[MAXN+MAXM];
    struct Link_Cut_Tree{
        int son[2];
        int f,v,flag;
    }a[MAXN+MAXM];
    inline bool isroot(int rt){
        return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
    }
    inline void pushup(int rt){
        if(!rt)return;
        a[rt].v=rt;
        if(val[a[rt].v]>val[a[a[rt].son[0]].v])a[rt].v=a[a[rt].son[0]].v;
        if(val[a[rt].v]>val[a[a[rt].son[1]].v])a[rt].v=a[a[rt].son[1]].v;
    }
    inline void pushdown(int rt){
        if(!rt||!a[rt].flag)return;
        a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
        swap(a[rt].son[0],a[rt].son[1]);
    }
    inline void turn(int rt){
        int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
        if(!isroot(x)){
            if(a[y].son[0]==x)a[y].son[0]=rt;
            else a[y].son[1]=rt;
        }
        a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
        a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
        pushup(x);pushup(rt);
    }
    void splay(int rt){
        top=0;
        stack[++top]=rt;
        for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
        while(top)pushdown(stack[top--]);
        while(!isroot(rt)){
            int x=a[rt].f,y=a[x].f;
            if(!isroot(x)){
                if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
                else turn(x);
            }
            turn(rt);
        }
    }
    void access(int rt){
        for(int i=0;rt;i=rt,rt=a[rt].f){
            splay(rt);
            a[rt].son[1]=i;
            pushup(rt);
        }
    }
    inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;}
    int find(int rt){
        access(rt);splay(rt);
        while(a[rt].son[0])rt=a[rt].son[0];
        return rt;
    }
    inline void split(int x,int y){makeroot(x);access(y);splay(y);}
    inline void link(int x,int y){makeroot(x);a[x].f=y;}
    inline void cut(int x,int y){split(x,y);a[x].f=a[y].son[0]=0;}
    inline int query(int x,int y){split(x,y);return a[y].v;}
}
inline void add(int u,int v,int w){
    top++;
    a[top].u=u;a[top].v=v;a[top].w=w;
}
void work(){
    int x,y;
    for(int i=1;i<=m;i++){
        x=que[i].x;y=que[i].y;
        if(que[i].f==0){
            if(LCT::find(x)!=LCT::find(y)){
                LCT::link(x,que[i].id+n);
                LCT::link(y,que[i].id+n);
            }
            else{
                int k=LCT::query(x,y);
                if(val[k]<a[que[i].id].w){
                    LCT::cut(a[k-n].u,k);
                    LCT::cut(a[k-n].v,k);
                    LCT::link(x,que[i].id+n);
                    LCT::link(y,que[i].id+n);
                }
            }
        }
        else if(que[i].f==1){
            LCT::cut(x,que[i].id+n);
            LCT::cut(y,que[i].id+n);
        }
        else if(que[i].f==2){
            if(LCT::find(x)==LCT::find(y))printf("Y\n");
            else printf("N\n");
        }
    }
}
void init(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        que[i].f=read();que[i].x=read();que[i].y=read();
        if(que[i].x>que[i].y)swap(que[i].x,que[i].y);
        if(que[i].f==0){
            add(que[i].x,que[i].y,MAX);
            add_time[que[i].x][que[i].y]=top;
            que[i].id=top;
        }
        if(que[i].f==1){
            int x=add_time[que[i].x][que[i].y];
            a[x].w=i;
            que[i].id=x;
        }
    }
    for(int i=0;i<=n;i++){
        val[i]=MAX+1;
        LCT::a[i].v=i;
    }
    for(int i=1;i<=top;i++){
        val[i+n]=a[i].w;
        LCT::a[i+n].v=i+n;
    }
}
int main(){
    init();
    work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Yangrui-Blog/p/9370724.html
今日推荐