Luogu2542 [AHOI2005]航线规划

Link

Solution

LCT维护边双的裸题。每次的答案是路径上边双数量-1。

维护边双可以用并查集维护,每次操作就直接作用在边双的代表元素上就行了。因为怕自己漏掉一些\(find()\),导致没有在代表元素上操作,干脆就丧心病狂地在进入任意函数的时候都\(find()\)一遍(反正复杂度也很低就是了)。当然除了缩点的函数\(combine()\)。还有,似乎涉及到父亲的都需要\(find()\)

另外就是缩点之后代表元素要继承splay根节点的父亲,然后实儿子全都断掉。因为缩点就是把整个splay中的点缩成一个点,所以原本的实边关系都消失,只剩下虚边关系。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define REP(i,a,b) for(int i=(a),ed=(b);i<=ed;++i)
inline int read(){
    register int x=0,f=1;register char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
    return f?x:-x;
}

const int N=3e4+10,M=1e5+10;
int n,m,t,ans[N],tp;
map<pair<int,int>,int> h;
struct node{int op,x,y;}e[M],q[M];

namespace LinkCutTree{
    int fa[N],ch[N][2],f[N],r[N],s[N];
    inline int find(int x){return f[x]=f[x]==x?f[x]:find(f[x]);}
    inline void pushup(int x){s[x]=s[ch[x][0]]+s[ch[x][1]]+1;}
    inline void pushr(int x){swap(ch[x][0],ch[x][1]),r[x]^=1;}
    inline void pushdown(int x){if(r[x])pushr(ch[x][0]),pushr(ch[x][1]),r[x]=0;}
    inline int getdir(int x){return x==ch[find(fa[x])][1];}
    inline bool noroot(int x){return x==ch[find(fa[x])][0]||x==ch[find(fa[x])][1];}
    inline void rotate(int x){
        x=find(x);int f=find(fa[x]),p=find(fa[f]),k=getdir(x),s=ch[x][!k];
        ch[x][!k]=f;ch[f][k]=s;if(noroot(f))ch[p][getdir(f)]=x;
        fa[f]=x;fa[x]=p;if(s)fa[s]=f;
        pushup(f);
    }
    inline void splay(int x){
        static int stk[N];
        x=find(x);int tp=0,y=x;stk[++tp]=y;
        while(noroot(y))stk[++tp]=y=find(fa[y]);
        while(tp)pushdown(stk[tp--]);
        for(int f=find(fa[x]);noroot(x);rotate(x),f=find(fa[x]))
            if(noroot(f))rotate(getdir(f)==getdir(x)?f:x);
        pushup(x);
    }
    inline void access(int x){
        x=find(x);
        for(int y=0;x;y=x,x=find(fa[x]))
            splay(x),ch[x][1]=y,pushup(x);
    }
    inline void makeroot(int x){
        x=find(x);access(x);splay(x);pushr(x);
    }
    inline int findroot(int x){
        x=find(x);access(x);splay(x);
        while(ch[x][0])pushdown(x),x=ch[x][0];
        splay(x);return x;
    }
    inline void split(int x,int y){
        x=find(x),y=find(y);makeroot(x);access(y);splay(y);
    }
    inline void combine(int x){
        pushdown(x);
        if(ch[x][0])f[find(ch[x][0])]=find(x),combine(ch[x][0]);
        if(ch[x][1])f[find(ch[x][1])]=find(x),combine(ch[x][1]);
    }
    inline void link(int x,int y){
        x=find(x),y=find(y);if(x==y)return;
        makeroot(x);
        if(findroot(y)^x)fa[x]=y;
        else{
            split(x,y);combine(y);
            int t=find(y);
            fa[t]=find(fa[y]);ch[t][0]=ch[t][1]=0;
            pushup(t);
        }
    }
}using namespace LinkCutTree;

int main(){
    n=read(),m=read();
    REP(i,1,m){
        e[i]=(node){0,read(),read()};
        if(e[i].x>e[i].y)swap(e[i].x,e[i].y);
        h[make_pair(e[i].x,e[i].y)]=i;
    }
    while(1){
        int op=read();if(!~op)break;
        q[++t]=(node){op,read(),read()};
        if(q[t].x>q[t].y)swap(q[t].x,q[t].y);
        if(!op)e[h[make_pair(q[t].x,q[t].y)]].op=1;
    }
    REP(i,1,n)f[i]=i;
    REP(i,1,m)if(!e[i].op)link(e[i].x,e[i].y);
    while(t){
        int x=find(q[t].x),y=find(q[t].y);
        if(q[t].op){
            split(x,y);
            ans[++tp]=s[y]-1;
        }
        else link(x,y);
        --t;
    }
    while(tp)printf("%d\n",ans[tp--]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fruitea/p/12129079.html
今日推荐