• luogu 2542 [AHOI2005]航线规划


    题目链接:luogu2542

    先考虑没有修改操作应该如何完成询问:使用(Tarjan)对点双进行缩点,答案就是缩完点后两点之间的距离

    再考虑有修改的情况,注意到修改只有删除一种操作,于是可以考虑倒序加边

    使用(LCT)维护这个加边的过程,考虑每一次加边对图中点双的影响:如果连成了一个环,那么就将这个环缩成一个点

    采用线段树打标记的思想,我们再开一个并查集,来维护缩点之后每个点的编号。具体的,对于每次加边,我们先找到连边的两点在缩完点之后的编号,若不在一个连通块的话则直接连边,否则就要考虑在并查集上打上缩点的tag。注意到我们(makeroot(x),access(y))之后这棵splay维护的就是(x->y)的链了,于是直接暴力的将(x)的右儿子清空,并在并查集上将它们的父亲置为(x)

    但这只是一个打标记的过程,我们并没有对子树信息做实质性的修改

    由于查询子树信息时都需要(access),于是可以在这个上面动手,将原来的(x=fa[x])变成(fa[x])缩成的那个点即可

    具体的更多细节看代码

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<math.h>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    const int N=10000;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define fir first
    #define sec second
    #define mp(a,b) make_pair(a,b)
    #define pb(a) push_back(a)
    #define maxd 998244353
    #define eps 1e-8
    struct node{
        int u,v;
    }edge[200200];
    struct qnode{
        int op,x,y;
    }q[200200];
    int n,m,siz[30050],fa[30030],ch[30030][2],pa[30030],tag[30030],sta[30030],tot=0,tot1=0,ans[40030];
    map<pair<int,int>,int> used;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    bool isroot(int x) {return ((ch[fa[x]][0]!=x) && (ch[fa[x]][1]!=x));}
    void pushup(int x) {siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
    void puttag(int x) {swap(ch[x][0],ch[x][1]);tag[x]^=1;}
    int find(int x) {if (pa[x]==x) return x;pa[x]=find(pa[x]);return pa[x];}
    void pushdown(int x)
    {
        if (tag[x])
        {
            if (ch[x][0]) puttag(ch[x][0]);
            if (ch[x][1]) puttag(ch[x][1]);
            tag[x]=0;
        }
    }
    
    void rotate(int x)
    {
        int y=fa[x],z=fa[y],k=(ch[y][1]==x),w=ch[x][k^1];
        if (!isroot(y)) ch[z][ch[z][1]==y]=x;
        ch[x][k^1]=y;ch[y][k]=w;
        if (w) fa[w]=y;fa[y]=x;fa[x]=z;
        pushup(y);pushup(x);
    }
    
    void splay(int x)
    {
        int now=x,tp=0;sta[++tp]=now;
        while (!isroot(now)) {now=fa[now];sta[++tp]=now;}
        while (tp) {pushdown(sta[tp]);tp--;}
        while (!isroot(x))
        {
            int y=fa[x],z=fa[y];
            if (!isroot(y))
            {
                if ((ch[y][0]==x)^(ch[z][0]==y)) rotate(x);else rotate(y);
            }
            rotate(x);
        }
        pushup(x);
    }
    
    void access(int x)
    {
        int y=0;
        while (x)
        {
            splay(x);ch[x][1]=y;pushup(x);
            y=x;fa[y]=find(fa[y]);x=find(fa[x]);
        }
    }
    
    int findroot(int x)
    {
        access(x);splay(x);
        while (ch[x][0])
        {
            pushdown(x);x=ch[x][0];
        }
        splay(x);return x;
    }
    
    void makeroot(int x) {access(x);splay(x);puttag(x);}
    void split(int x,int y) {makeroot(x);access(y);splay(y);}
    void del(int x,int fx) {if (x) {pa[x]=fx;del(ch[x][0],fx);del(ch[x][1],fx);}}
    void link(int x,int y)
    {
        if (x==y) return;
        makeroot(x);
        if (findroot(y)!=x)
        {
            fa[x]=y;pushup(y);
        }
        else
        {   
            del(ch[x][1],x);
            ch[x][1]=0;pushup(x);
        }
    }
    
    int main()
    {
        n=read();m=read();
        rep(i,1,m)
        {
            edge[i].u=read();edge[i].v=read();
        }
        while (1)
        {
            int op=read();if (op==-1) break;
            q[++tot].op=op;
            q[tot].x=read();q[tot].y=read();
            if (!op) used[mp(q[tot].x,q[tot].y)]=used[mp(q[tot].x,q[tot].y)]=1;
        }
        rep(i,1,n) {siz[i]=1;pa[i]=i;}
        rep(i,1,m)
        {
            if (used.count(mp(edge[i].u,edge[i].v))==0) 
            {
                int fx=find(edge[i].u),fy=find(edge[i].v);
                link(fx,fy);
            }
        }
        per(i,tot,1)
        {
            int fx=find(q[i].x),fy=find(q[i].y);
            if (q[i].op)
            {
                split(fx,fy);ans[++tot1]=siz[fy]-1;
            }
            else link(fx,fy);
            //rep(j,1,n) cout << find(j) << " ";cout << endl;
        }
        per(i,tot1,1) printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    Haproxy的安装与配置
    keepalived工作原理和配置说明
    服务器集群与负载均衡基础知识
    Linux磁盘分区与格式化
    第12章 在.NET中操作XML
    第16章 多线程
    第10章 网络编程
    第8章 流和序列化
    关于引用类型作为参数加上ref与不加ref的区别
    第3章 C#中的委托和事件
  • 原文地址:https://www.cnblogs.com/encodetalker/p/11071755.html
Copyright © 2020-2023  润新知