zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    SharePoint 2013 APP 开发示例 (六)服务端跨域访问 Web Service (REST API)
    麦咖啡导致电脑不能上网
    SharePoint 2013 Central Admin 不能打开
    SharePoint 2013 APP 开发示例 (五)跨域访问 Web Service (REST API)
    SharePoint 2013 APP 开发示例 系列
    synthesize(合成) keyword in IOS
    Git Cmd
    简单的正则匹配
    Dropbox
    SQL Server Replication
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8329613.html
Copyright © 2011-2022 走看看