• [LOJ2230][BJOI2014]大融合


    题面戳我

    sol

    LCT维护子树size。
    开一个数组(sz_i)表示一个节点的所有虚儿子的size和,(sum_i)表示以一个节点为根的子树的(size)和,可见(sz_u=sum_{vmbox{是}umbox{的虚儿子}}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
    ",1ll*sum[u]*(sum[v]-sum[u]));
    	}
    	return 0;
    }
    
  • 相关阅读:
    分析ARP攻击与欺骗
    IP数据包结构
    OSI 7层模型
    PKI
    求一个字符串所有的子序列:非递归和递归算法
    空当接龙求解:java版广度优先
    mysql 解决奇葩问题续篇。
    mysql 的一个奇葩问题
    symfony 之 admin 征途二 数据库相关
    symfony 之 admin 征途一 试运行
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8329613.html
Copyright © 2020-2023  润新知