zoukankan      html  css  js  c++  java
  • bzoj4530:[Bjoi2014]大融合

    传送门

    题意:

    一开始有n棵单点的树,每次连接两个点(保证仍未树结构),或者询问某课树中经过某条边的简单路径条数。

    lct维护子树信息。

    一个点维护两个值sum表示子树信息,sz表示它所有虚儿子的信息,sum[x]=sum[lc]+sum[rc]+sz[x]+1;

    发现仅有access和link时sz会改变。(cut时切掉的是实儿子)

    access是把右儿子换成t,sz[x]就减去sum[t],加上sum[rc];

    link时给x接上新的虚儿子y,就sz[x]+=sum[y],但是要先把access再splay到跟,因为不然x的父亲往上的信息也需要要改。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<ctime>
    #define For(i,a,b) for(int i=(a);i<=(b);i++)
    #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
    const int N=3e5+7;
    typedef long long LL;
    typedef double db;
    using namespace std;
    int n,m,v[N],ch[N][2],p[N],sum[N],flip[N],sz[N];
    char o[5];
    
    template<typename T> void read(T &x) {
        T f=1; x=0; char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    #define lc ch[x][0]
    #define rc ch[x][1]
    int isroot(int x) { return (ch[p[x]][0]!=x&&ch[p[x]][1]!=x); }
    
    void update(int x) { sum[x]=sum[lc]+sum[rc]+sz[x]+1; } //sum:总信息 sz:虚儿子信息 
    
    void down(int x) {
        if(!flip[x]) return;
        swap(lc,rc);
        flip[x]^=1;
        flip[lc]^=1;
        flip[rc]^=1;
    } 
    
    void rotate(int x) {
        int y=p[x],z=p[y],l=(x==ch[y][1]),r=l^1;
        if(!isroot(y)) ch[z][y==ch[z][1]]=x; p[x]=z;
        ch[y][l]=ch[x][r]; p[ch[x][r]]=y;
        ch[x][r]=y; p[y]=x;
        update(y); update(x);
    }
    
    void splay(int x) {
        static int g[N],top=0,tp;
        for(tp=x;!isroot(tp);tp=p[tp]) g[++top]=tp;
        g[++top]=tp;
        while(top) {down(g[top--]);}
        for(;!isroot(x);rotate(x)) {
            int y=p[x],z=p[y];
            if(!isroot(y)) 
                ((x==ch[y][1])^(y==ch[z][1]))?rotate(x):rotate(y);
        }
    }
    
    void access(int x) {
        for(int t=0;x;x=p[t=x]) {
            splay(x);
            sz[x]+=sum[rc]-sum[t]; 
            rc=t;
            update(x);
        }
    }
    
    void newroot(int x) {
        access(x);
        splay(x);
        flip[x]^=1;
    }
    
    void lik(int x,int y) {
        newroot(x); newroot(y);
        splay(x); p[x]=y; 
        sz[y]+=sum[x]; update(y);
    }
    
    
    int main() {
        read(n); read(m);
        for(int i=1;i<=n;i++) update(i);
        while(m--) {
            scanf("%s",o); 
            int x,y;
            read(x); read(y); 
            if(o[0]=='A') lik(x,y);    
            else {
                newroot(x); newroot(y);
                printf("%lld
    ",(LL)sum[x]*(sum[y]-sum[x]));
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Shell,Bash,等脚本学习(有区别)
    nfs 服务器
    awk的简单使用
    GPRS研究(3):NO CARRIER错误的含义解释
    信号量
    Linux 的多线程编程的高效开发经验
    getaddrinfo()函数详解
    iOS 知识点
    UITableView拉伸效果
    在Xcode中使用Git进行源码版本控制
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8543615.html
Copyright © 2011-2022 走看看