zoukankan      html  css  js  c++  java
  • 洛谷4219 BJOI2014大融合(LCT维护子树信息)

    QWQ

    这个题目是LCT维护子树信息的经典应用

    根据题目信息来看,对于一个这条边的两个端点各自的(size)乘起来,不过这个应该算呢?

    我们可以考虑在LCT上多维护一个(xv[i])表示(i)的虚子树的子树和,然后维护(sum[i])表示(i)的虚+实子树之和。

    那么对于一个点(x),他在原树上的字数大小就应该是$$size = xv[x]+sum[ch[x][1]]+1$$

    这是个经典套路!

    对于这个题来说,我们可以通过(split(x,y)),然后(ans)就等于((xv[x]+1) imes (xv[y]+1))
    这个地方可以理解为,x的虚儿子是以x为根,不经过((x,y))这条边的 所有子树和,正好符合题目要求,y也是同理。

    当然,也存在别的计算方法:我们(makeroot(y)),然后直接用x的子树大小,乘上y的子树大小减去x的。也是可以的。道理和上面的类似

    直接上代码

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<set>
    
    using namespace std;
    
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    
    const int maxn = 2e5+1e2;
    
    int size[maxn];
    int xv[maxn];
    int ch[maxn][3];
    int fa[maxn];
    int n,m,cnt;
    int st[maxn];
    int rev[maxn];
    
    int son(int x)
    {
    	if (ch[fa[x]][0]==x) return 0;
    	else return 1;
    }
    
    bool notroot(int x)
    {
    	return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
    }
    
    void update(int x)
    {
    	size[x]=size[ch[x][0]]+size[ch[x][1]]+xv[x]+1;
    }
    
    void reverse(int x)
    {
    	swap(ch[x][0],ch[x][1]);
    	rev[x]^=1;
    }
    
    void pushdown(int x)
    {
    	if (rev[x])
    	{
    		if (ch[x][0]) reverse(ch[x][0]);
    		if (ch[x][1]) reverse(ch[x][1]);
    		rev[x]=0;
    	}
    }
    
    void rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	int b=son(x),c=son(y);
    	if (notroot(y)) ch[z][c]=x;
    	fa[x]=z;
    	ch[y][b]=ch[x][!b];
    	fa[ch[x][!b]]=y;
    	ch[x][!b]=y;
    	fa[y]=x;
    	update(y);
    	update(x);
    }
    
    void splay(int x)
    {
    	int y=x,cnt=0;
    	st[++cnt]=y;
    	while (notroot(y)) y=fa[y],st[++cnt]=y;
    	while (cnt) pushdown(st[cnt--]);
    	while (notroot(x))
    	{
    		int y=fa[x],z=fa[y];
    		int b=son(x),c=son(y);
    		if (notroot(y))
    		{
    			if (b==c) rotate(y);
    			else rotate(x);
    		}
    		rotate(x);
    	}
    	update(x);
    }
    
    void access(int x)
    {
    	for (int y=0;x;y=x,x=fa[x])
    	{
    		splay(x);
    		xv[x]+=size[ch[x][1]];
    		ch[x][1]=y;
    		xv[x]-=size[y];
    	}
    }
    
    void makeroot(int x)
    {
    	access(x);
    	splay(x);
    	reverse(x);
    }
    
    int findroot(int x)
    {
    	access(x);
    	splay(x);
    	while (ch[x][0])
    	{
    		pushdown(x);
    		x=ch[x][0];
    	}
    	return x;
    }
    
    void split(int x,int y)
    {
    	makeroot(x);
    	access(y);
    	splay(y);
    }
    
    void link(int x,int y)
    {
      split(x,y);
      if (findroot(y)!=x)
      {
      	fa[x]=y;
      	xv[y]+=size[x];
      }
      update(y);
    }
    
    int q;
    
    int main()
    {
       n=read(),q=read();
       for (int i=1;i<=q;i++) 
       {
       	 char s[10];
       	 scanf("%s",s+1);
       	 if (s[1]=='A')
       	 {
       	 	 int x=read(),y=read();
       	 	 link(x,y);
    	 }
    	 else
    	 {
    	 	int x=read(),y=read();
    	 	split(x,y);
    	 	printf("%lld
    ",1ll*(xv[x]+1)*(xv[y]+1));
    	 }
       }
       return 0;
    }
    
    
  • 相关阅读:
    自定义ckeditor5
    ckEditor5 图片上传到七牛云
    Vue2.0原理-指令
    小程序体积优化(1)--优化大文本
    win10系统安装docker注意事项
    Vue2.0原理-模板解析
    使用nginx部署静态网站
    react-native初体验(2) — 认识路由
    react-native初体验(1) — hello world
    领骑衫总结
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161450.html
Copyright © 2011-2022 走看看