• BZOJ_4530_[Bjoi2014]大融合_LCT


    BZOJ_4530_[Bjoi2014]大融合_LCT

    Description

    小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。
    这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够
    联通的树上路过它的简单路径的数量。
    例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因
    为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8)。
    现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的
    询问。

    Input

    第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
    接下来的Q行,每行是如下两种格式之一:
    A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
    Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
    1≤N,Q≤100000

    Output

    对每个查询操作,输出被查询的边的负载。

    Sample Input

    8 6
    A 2 3
    A 3 4
    A 3 8
    A 8 7
    A 6 5
    Q 3 8

    Sample Output

    6


    我们都知道正常LCT维护的是一些链的信息。

    splay的根不一定连向树上的儿子,这样丢失了儿子的信息。因此无法维护子树信息。

    需要在一些操作中加入对子树信息的变动。

    设all[x]为x子树结点个数,siz[x]为x子树不在链上结点个数。

    注意到access操作割掉了rs加入了t,因此不在链上结点个数需要加rs减去t。

    然后link操作也改变了子树信息,需要对两个结点分别更新,makeroot两次即可。

    上传函数也改一下。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 100050
    #define ls ch[p][0]
    #define rs ch[p][1]
    #define get(x) (ch[f[x]][1]==x)
    int ch[N][2],f[N],rev[N],siz[N],all[N],n,m;
    char opt[10];
    inline bool isrt(int p) {
        return ch[f[p]][0]!=p&&ch[f[p]][1]!=p;
    }
    inline void pushdown(int p) {
        if(rev[p]) {
            swap(ch[ls][0],ch[ls][1]); swap(ch[rs][0],ch[rs][1]);
            rev[ls]^=1; rev[rs]^=1; rev[p]=0;
        }
    }
    inline void pushup(int p) {
        all[p]=all[ls]+all[rs]+siz[p]+1;
    }
    void update(int p) {
        if(!isrt(p)) update(f[p]);
        pushdown(p);
    }
    void rotate(int x) {
        int y=f[x],z=f[y],k=get(x);
        if(!isrt(y)) ch[z][ch[z][1]==y]=x;
        ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
        ch[x][!k]=y; f[y]=x; f[x]=z;
        pushup(y); pushup(x);
    }
    void splay(int x) {
        update(x);
        for(int fa;fa=f[x],!isrt(x);rotate(x))
            if(!isrt(fa))
                rotate(get(fa)==get(x)?fa:x);
    }
    void access(int p) {
        int t=0;
        while(p) splay(p),siz[p]+=all[rs]-all[t],rs=t,pushup(p),t=p,p=f[p];
    }
    void makeroot(int p) {
        access(p); splay(p); swap(ls,rs); rev[p]^=1;
    }
    void link(int x,int p) {
        makeroot(x); makeroot(p); f[x]=p; siz[p]+=all[x]; pushup(p);
    }
    int main() {
        scanf("%d%d",&n,&m);
        int i,x,y;
        for(i=1;i<=n;i++) all[i]=1;
        for(i=1;i<=m;i++) {
            scanf("%s%d%d",opt,&x,&y);
            if(opt[0]=='A') {
                link(x,y);
            }else {
                makeroot(x); makeroot(y);
                printf("%lld
    ",1ll*all[x]*(all[y]-all[x]));
            }
        }
    }
    
    
  • 相关阅读:
    重新了解Java基础(六)-Java关键字
    重新了解Java基础(五)-Java标识符
    重新了解Java基础(四)-常用开发工具&注释简介
    CentOS 7 安装JDK
    一步一步教你自定义博客园(cnblog)界面
    如何设置文字的阴影
    如何实现2D动画
    跳转九宫格的制作
    风车的动图制作
    心跳的动图制作
  • 原文地址:https://www.cnblogs.com/suika/p/8967924.html
Copyright © 2020-2023  润新知