码迷,mamicode.com
首页 > 其他好文 > 详细

[LOJ2230][BJOI2014]大融合

时间:2018-01-22 17:27:01      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:ref   down   ota   roo   默认   etc   +=   get   修改   

题面戳我

sol

LCT维护子树size。
开一个数组\(sz_i\)表示一个节点的所有虚儿子的size和,\(sum_i\)表示以一个节点为根的子树的\(size\)和,可见\(sz_u=\sum_{v\mbox{是}u\mbox{的虚儿子}}sum_v\)
那么我们就需要动态维护这两个东西,首先考虑\(sz_i\),这个只有在儿子的虚实关系被修改的时候才会变化,所以只有\(access\)\(link\)的时候会改变。在\(access\)中一定会是一个儿子由虚变实,一个儿子由实变虚。因为维护的是虚儿子的和,所以加上那个由实变虚的,减去那个由虚变实的。
\(link\)里面注意两个点都要\(makeroot\)一下,然后\(sz\)也要更新,因为\(link\)连接了以后是默认虚儿子。
\(sum_i\)就有一个递推式直接\(pushup\)就好了。
\[sum_x=sum_{ls_x}+sum_{rs_x}+1+sz_x\]

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 200005;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
int n,q,fa[N],ls[N],rs[N],rev[N],sz[N],sum[N],Stack[N],top;
char s[1000];
bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
void pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]]+1+sz[x];}
void reverse(int x){swap(ls[x],rs[x]);rev[x]^=1;}
void pushdown(int x){if(!rev[x])return;if(ls[x])reverse(ls[x]);if(rs[x])reverse(rs[x]);rev[x]=0;}
void R_rotate(int x)
{
    int y=fa[x],z=fa[y];
    ls[y]=rs[x];
    if (rs[x]) fa[rs[x]]=y;
    fa[x]=z;
    if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x;
    rs[x]=y;fa[y]=x;
    pushup(y);
}
void L_rotate(int x)
{
    int y=fa[x],z=fa[y];
    rs[y]=ls[x];
    if (ls[x]) fa[ls[x]]=y;
    fa[x]=z;
    if (y==ls[z]) ls[z]=x;if (y==rs[z]) rs[z]=x;
    ls[x]=y;fa[y]=x;
    pushup(y);
}
void splay(int x)
{
    Stack[top=1]=x;
    for (int i=x;!isroot(i);i=fa[i])
        Stack[++top]=fa[i];
    while (top) pushdown(Stack[top--]);
    while (!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if (isroot(y))
            if (x==ls[y]) R_rotate(x);
            else L_rotate(x);
        else
            if (y==ls[z])
                if (x==ls[y]) R_rotate(y),R_rotate(x);
                else L_rotate(x),R_rotate(x);
            else
                if (x==ls[y]) R_rotate(x),L_rotate(x);
                else L_rotate(y),L_rotate(x);
    }
    pushup(x);
}
void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),sz[x]+=sum[rs[x]]-sum[y],rs[x]=y,pushup(x);}
void makeroot(int x){access(x);splay(x);reverse(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void link(int x,int y){makeroot(x);makeroot(y);fa[x]=y;sz[y]+=sum[x];pushup(y);}
int main()
{
    n=gi();q=gi();
    for (int i=1;i<=n;i++) sum[i]=1;
    while (q--)
    {
        scanf("%s",s);int u=gi(),v=gi();
        if (s[0]=='A') link(u,v);
        else split(u,v),printf("%lld\n",1ll*sum[u]*(sum[v]-sum[u]));
    }
    return 0;
}

[LOJ2230][BJOI2014]大融合

标签:ref   down   ota   roo   默认   etc   +=   get   修改   

原文地址:https://www.cnblogs.com/zhoushuyu/p/8329613.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!