bzoj3673-可持久化并查集

Description

BZOJ

Solution

并不要求在线, 然后就有很优秀 好写 的离线做法...

我们考虑把每个操作建成一个点 \(i\).

对于 \(1\)\(3\) 操作, 连边 \((i-1, i)\);

对于 \(2\) 操作, 连边 \((k_i, i)\).

容易发现这是一棵树, 并且并查集的操作可以回退, 那么我们直接在树上dfs, 在进入节点/回溯时处理merge/split/查询即可.

代码超短...

Code

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;

//---------------------------------------
const int nsz=2e4+50;
int n,m,ans[nsz],las;

int fa[nsz],dep[nsz];
int stk[nsz][2],top=0;
void init(){rep(i,1,n)fa[i]=i,dep[i]=1;}
int find(int p){return p==fa[p]?p:find(fa[p]);}
int iscon(int a,int b){return find(a)==find(b);}
void merge(int a,int b){
    a=find(a),b=find(b);
    if(a==b)return;
    if(dep[a]<dep[b])swap(a,b);
    stk[++top][0]=b,stk[top][1]=dep[a];
    fa[b]=a,dep[a]=max(dep[a],dep[b]+1);
}
void del(int top1){
    for(;top!=top1;--top){
        int a=stk[top][0],b=stk[top][1];
        dep[fa[a]]=b,fa[a]=a;
    }
}


struct tqu{int ty,a,b;}qu[nsz];
vector<int> ed[nsz];
void adde(int f,int t){ed[f].push_back(t);}

void dfs(int p){
    int top1=top;
    if(qu[p].ty==1)merge(qu[p].a,qu[p].b);
    else if(qu[p].ty==3)ans[p]=iscon(qu[p].a,qu[p].b);
    for(int v:ed[p]){
        dfs(v);
    }
    del(top1);
}

int main(){
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>n>>m;
    init();
    int a,b,c;
    rep(i,1,m){
        cin>>a>>b,qu[i].ty=a,qu[i].a=b;
        if(a==2)adde(b,i);
        else cin>>c,qu[i].b=c,adde(las,i);
        las=i;
    }
    dfs(0);
    rep(i,1,m)if(qu[i].ty==3)cout<<ans[i]<<'\n';
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ubospica/p/10645546.html