【[BJOI2014]大融合】LCT维护子树(虚边信息)

LCT维护子树信息的好题~~

luogu传送门:https://www.luogu.org/problemnew/show/P4219

这个方法是从这篇博文里学到的%%%https://blog.csdn.net/neither_nor/article/details/52979425

大概就是多开一个数组维护虚边上的信息(本题是虚边上点的数量)

考虑哪些操作会影响虚边上的信息:——》Access和link

Access时会将原本实边切换成虚边,把原本虚边切换成实边。那么直接信息里减去原本的信息再加上现在的信息就是了

而link操作则相较之比较麻烦解决。主要是如果将y设为虚边x的父亲之后,y的祖先节点们也需要随之更改信息。因此我们在原本只setroot(x)的link基础上添加关于y的操作---> access(y)+splay(y)这样就将y设置成了根节点就不用考虑更新祖先节点的问题了。

而其他的操作实际稍加考虑就会发现不会涉及虚实问题。

再讲这道题,很容易发现就是边左右子树大小相乘就是了,实现用上LCT维护子树。 答案时,setroot(x) access(y) splay(y) 然后答案就是(虚子树节点y+1)*(虚子树节点x+1)

talk is cheap,show me code!

#include<bits/stdc++.h>
using namespace std;
int n,q;
const int maxn = (int) 1e5;
int fa[maxn],ls[maxn],rev[maxn],rs[maxn],trsiz[maxn],flsiz[maxn];
#define zig(x) zigzag(x,1)
#define zag(x) zigzag(x,2)
bool isroot(int x) { return ls[fa[x]]!=x&&rs[fa[x]]!=x; }
void putup(int x)
{ trsiz[x]=trsiz[ls[x]]+trsiz[rs[x]]+flsiz[x]+1; }
void putdowm(int x)
{
    if(!rev[x]) return;
    swap(ls[x],rs[x]);
    rev[ls[x]]^=1; rev[rs[x]]^=1; rev[x]=0;
}
void zigzag(int x,int knd)
{
    int y=fa[x],z=fa[y];
    if(!isroot(y))
    {
        if(ls[z]==y) ls[z]=x;
        else rs[z]=x;
    }
    fa[x]=z; fa[y]=x;
    if(knd==1)
    {
        ls[y]=rs[x];
        fa[ls[y]]=y;
        rs[x]=y;
    }
    else
    {
        rs[y]=ls[x];
        fa[rs[y]]=y;
        ls[x]=y;
    }
    putup(y); putup(x);
}
void putdowmall(int x)
{
    if(!isroot(x)) putdowmall(fa[x]);
    putdowm(x); 
}
void splay(int x)
{
    putdowmall(x);
    int y,z;
    while(!isroot(x))
    {
        y=fa[x]; z=fa[y];
        if(isroot(y))
        {
            if(ls[y]==x) zig(x);
            else zag(x);
        }
        else
        {
            if(ls[z]==y)
            {
                if(ls[y]==x) { zig(y); zig(x); }
                else { zag(x); zig(x); } 
            }
            else
            {
                if(rs[y]==x) { zag(y); zag(x); }
                else { zig(x); zag(x); }
            }
        }
    }
}
void acc(int x)
{
    for(int y=0;x;y=x,x=fa[x])
    {
        splay(x);
        flsiz[x]+=trsiz[rs[x]];
        flsiz[x]-=trsiz[y];
        rs[x]=y;
    }
}
void setroot(int x)
{
    acc(x); splay(x); rev[x]^=1;
}
void link(int x,int y)
{
    setroot(x); acc(y); splay(y);
    fa[x]=y; flsiz[y]+=trsiz[x];
    putup(y);
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) trsiz[i]=1;
    char ss[5];
    int x,y;
    for(int i=1;i<=q;i++)
    {
        scanf("%s%d%d",ss,&x,&y);
        if(ss[0]=='A') 
        {
            link(x,y);
        }
        else
        {
            setroot(x); acc(y); splay(y);
            printf("%d\n",(flsiz[y]+1)*(flsiz[x]+1));
        }
    }
}

 

posted @ 2018-04-05 19:13  Newuser233  阅读(12)  评论(0)    收藏  举报