zoukankan      html  css  js  c++  java
  • 洛谷P4219

    Portal

    Description

    初始有(n(nleq10^5))个孤立的点,进行(Q(Qleq10^5))次操作:

    • 连接边((u,v)),保证(u,v)不连通。
    • 询问有多少条简单路径经过边((u,v))

    Solution

    加边用lct,询问结果相当于(p)为根时的((siz[p]-siz[q]) imes siz[q])
    那么如何用lct维护子树大小呢?维护(isiz[p])表示(p)在lct上的虚子树大小,(siz[p])表示(isiz[p])加上在辅助树上的实子树大小(子树大小也包括子树的虚子树和实子树)。当(p=rt)(p)没有实子树时,(siz[p])等于其原树上的子树大小。
    如何维护(isiz)呢?只有当树的虚实划分变化时,(isiz)才会变化,也就是accesslinkaccess(p)中有一句ch[p][1]=q,说明(ch[p][1])变为虚子树,(q)变为实子树,则isiz[p]+=siz[ch[p][1]]-siz[q]link(p,q)(p)变为(q)的虚子树,因此(q)(q)的根的(isiz)都要改变;因为不好实现所以makeRt(q)之后再连接,并isiz[q]+=siz[p]
    询问时,只要makeRt(p),access(q),splay(q),此时(q=rt)(p)没有实子树,(siz)均正确。

    时间复杂度(O(Qlogn))

    Code

    //[BJOI2014]大融合
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int read()
    {
        int x=0; char ch=getchar();
        while(ch<'0'||'9'<ch) ch=getchar();
        while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    int const N=1e5+10;
    int n,Q;
    int fa[N],ch[N][2],siz[N],isiz[N]; bool rev[N];
    int wh(int p) {return p==ch[fa[p]][1];}
    int notRt(int p) {return p==ch[fa[p]][wh(p)];}
    void rever(int p) {rev[p]^=1; swap(ch[p][0],ch[p][1]);}
    void update(int p) {siz[p]=siz[ch[p][0]]+siz[ch[p][1]]+isiz[p]+1;}
    void pushdw(int p) {if(rev[p]) rever(ch[p][0]),rever(ch[p][1]),rev[p]=false;}
    void rotate(int p)
    {
        int q=fa[p],r=fa[q],w=wh(p);
        fa[p]=r; if(notRt(q)) ch[r][wh(q)]=p;
        fa[ch[q][w]=ch[p][w^1]]=q;
        fa[ch[p][w^1]=q]=p;
        update(q),update(p);
    }
    void pushdwRt(int p) {if(notRt(p)) pushdwRt(fa[p]); pushdw(p);}
    void splay(int p)
    {
        pushdwRt(p);
        for(int q=fa[p];notRt(p);rotate(p),q=fa[p]) if(notRt(q)) rotate(wh(p)^wh(q)?p:q);
    }
    void access(int p) {for(int q=0;p;q=p,p=fa[p]) splay(p),isiz[p]+=siz[ch[p][1]]-siz[q],ch[p][1]=q,update(p);}
    void makeRt(int p) {access(p),splay(p),rever(p);}
    void link(int p,int q) {makeRt(p),makeRt(q); fa[p]=q,isiz[q]+=siz[p]; update(q);}
    long long query(int p,int q) {makeRt(p),access(q),splay(q); return (long long)siz[p]*(siz[q]-siz[p]);}
    int main()
    {
        n=read(),Q=read();
        for(int i=1;i<=n;i++) siz[i]=1;
        for(int i=1;i<=Q;i++)
        {
            char opt[5]; scanf("%s",opt);
            int u=read(),v=read();
            if(opt[0]=='A') link(u,v);
            else printf("%lld
    ",query(u,v));
        }
        return 0;
    }
    

    P.S.

    比Icefox短了20行!

  • 相关阅读:
    Android 查看APK文件的签名算法
    Android 查看App冷启动时间/热启动时间/页面打开时间
    Android 查看Apk签名方式V1和V2
    Android App启动速度优化
    Android SharedPreferences中apply和commit的效率差距
    Gralde 网络代理
    Git 将子文件夹分离为一个新的库
    Fabric-Crashlytics-Android 注意点
    Gradle编译失败 generating the main dex list
    Gralde 同步失败
  • 原文地址:https://www.cnblogs.com/VisJiao/p/LgP4219.html
Copyright © 2011-2022 走看看