【BJOI 2014】大融合

Description

初始有N个点,接下来Q个操作,有两种操作
1 将不连通的x,y连边
2 询问经过边(x,y)的简单路径数量
对于100%的数据,1≤N,Q≤100000

链剖

所谓简单路径数量,就是从中间的边分开,两边的连通块点数之积
先把最终的树弄出来,转成有根树
链剖,每个点维护其子树大小
然后可以发现,连边后对于某一段链的子树大小是会有影响的
借助并查集来确定这一段范围

动态树

实现带有子树大小查询功能的LCT
size[x]表示x在辅助splay上的子树大小
s[x]表示x的虚儿子子树大小和
则求x的子树大小,可以先access(x),然后返回s[x]+1
all[x]=1+s[x]+all[leftson]+all[rightson]
all[x]表示x点所在重链(形成辅助树)及其下方的结点总数
注意这样写如果要用all[x]去更新s[y],必须先splay(x)

Key codes

void update(int x)
{
    if(!x) return;
    size[x]=1+size[a[x][0]]+size[a[x][1]];
    all[x]=1+s[x]+all[a[x][0]]+all[a[x][1]];
}
void access(int x)
{
    for(int y=0;x;y=x,x=p[x])
    {
        splay(x,0);
        f[a[x][1]]=0,p[a[x][1]]=x;
        s[x]+=all[a[x][1]];
        a[x][1]=y,f[y]=x,p[y]=0;
        s[x]-=all[y];
        update(x);
    }
}
void makeroot(int x)
{
    access(x);splay(x,0);turn(x);
}
void link(int x,int y)
{
    makeroot(x);makeroot(y);p[x]=y;
    s[y]+=all[x];
    update(y);
}
int getsize(int x)
{
    access(x);
    return 1+s[x];
}

你可能感兴趣的:(题解,动态树,树链剖分)