[lct] Luogu P4219 大融合

题目描述

小强要在NN个孤立的星球上建立起一套通信系统。这套通信系统就是连接NN个点的一个树。 这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够 联通的树上路过它的简单路径的数量。

例如,在上图中,现在一共有了55条边。其中,(3,8)(3,8)这条边的负载是66,因 为有六条简单路径2-3-8238,2-3-8-72387,3-8,3-8-738,387,4-3-8438,4-3-8-74387路过了(3,8)(3,8)。

现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的 询问。

输入输出格式

输入格式:

 

第一行包含两个整数 N, QN,Q,表示星球的数量和操作的数量。星球从 11 开始编号。

接下来的 QQ 行,每行是如下两种格式之一:

  • A x y 表示在 xx和 yy 之间连一条边。保证之前 xx 和 yy是不联通的。
  • Q x y表示询问 (x,y)(x,y) 这条边上的负载。保证 xx 和 yy 之间有一条边。

 

输出格式:

 

对每个查询操作,输出被查询的边的负载。

 

输入输出样例

输入样例#1:
8 6
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8
输出样例#1:
6

说明

对于所有数据,1≤N,Q≤10^51N,Q105

 

题解

  • 对于lct一般都是维护链上的操作,那么怎么维护子树上的信息呢
  • 定义siz[x]表示x的所有虚儿子的子树大小和,size[x]表示x的所有虚儿子+实儿子+自己的子树大小和
  • 那么只要在虚实边变化的时候维护一下siz的大小,同时维护size就好了
  • 求x的子树大小,只要access(x),然后siz[x]+1就是答案了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define N 300010
 5 using namespace std;
 6 int n,m,f[N],ch[N][2],v[N],s[N],size[N],tag[N];
 7 int nroot(int x) { return ch[f[x]][0]==x||ch[f[x]][1]==x; }
 8 void pushup(int x) { size[x]=size[ch[x][0]]+size[ch[x][1]]+s[x]+1; }
 9 void pushdown(int x) { if (tag[x]) swap(ch[x][0],ch[x][1]),tag[ch[x][0]]^=1,tag[ch[x][1]]^=1,tag[x]=0; }
10 void work(int x) { if (nroot(x)) work(f[x]); pushdown(x); }
11 void rotate(int x)
12 {
13     int y=f[x],z=f[y],k=ch[y][1]==x,w=ch[x][!k];
14     if (nroot(y)) ch[z][ch[z][1]==y]=x;
15     ch[x][!k]=y,ch[y][k]=w,f[y]=x,f[x]=z;
16     if (w) f[w]=y;
17     pushup(y);
18 }
19 void splay(int x) { work(x); while (nroot(x)) rotate(x); pushup(x); }
20 void access(int x) { for (int y=0;x;x=f[y=x]) splay(x),s[x]+=size[ch[x][1]],s[x]-=size[ch[x][1]=y],pushup(x); }
21 void makeroot(int x) { access(x),splay(x),tag[x]^=1; }
22 void split(int x,int y) { makeroot(x),access(y),splay(y); }
23 void link(int x,int y) { split(x,y);s[f[x]=y]+=size[x],pushup(y); }
24 int main()
25 {
26     scanf("%d%d",&n,&m);
27     for (int i=1;i<=n;i++) size[i]=i;
28     for (int x,y;m;m--)
29     {
30         char ch=getchar(); while (ch!='A'&&ch!='Q') ch=getchar();
31         scanf("%d%d",&x,&y);
32         if (ch=='Q') split(x,y),printf("%lld\n",(s[x]+1)*(s[y]+1)); else link(x,y);
33     }
34 }

 

posted @ 2019-07-03 21:51  BEYang_Z  阅读(146)  评论(0编辑  收藏  举报