P4219 [BJOI2014]大融合 ( LCT维护虚实子树size )

题目描述

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

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

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

输入输出格式

输入格式:

 

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

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

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

 

输出格式:

 

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

 

输入输出样例

输入样例#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≤1051≤N,Q≤10^51N,Q105

SOLUTION:

lct在维护链的同时维护一个虚子树的信息

 

CODE:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #define R register int
 4 #define I inline void
 5 const int N=100009;
 6 int f[N],c[N][2],si[N],s[N];
 7 bool r[N];
 8 #define lc c[x][0]
 9 #define rc c[x][1]
10 inline bool nroot(R x){return c[f[x]][0]==x||c[f[x]][1]==x;}
11 I pushup(R x){
12     s[x]=s[lc]+s[rc]+si[x]+1;
13 }
14 I pushdown(R x){
15     if(r[x]){
16         R t=lc;lc=rc;rc=t;
17         r[lc]^=1;r[rc]^=1;r[x]=0;
18     }
19 }
20 I pushall(R x){
21     if(nroot(x))pushall(f[x]);
22     pushdown(x);
23 }
24 I rotate(R x){
25     R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
26     if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
27     f[w]=y;f[y]=x;f[x]=z;
28     pushup(y);
29 }
30 I splay(R x){//请忽略这个spaly
31     pushall(x);
32     while(nroot(x))rotate(x);
33     pushup(x);
34 }
35 I access(R x){
36     for(R y=0;x;x=f[y=x]){
37         splay(x);
38         si[x]+=s[rc];
39         si[x]-=s[rc=y];
40         //pushup(x);试着去掉,发现对答案无影响
41     }
42 }
43 I makeroot(R x){
44     access(x);splay(x);
45     r[x]^=1;
46 }
47 I split(R x,R y){
48     makeroot(x);
49     access(y);splay(y);
50 }
51 I link(R x,R y){
52     split(x,y);
53     si[f[x]=y]+=s[x];
54     pushup(y);
55 }//LCT模板到此结束
56 #define G ch=getchar()
57 #define gc G;while(ch<'-')G
58 #define in(z) gc;z=ch&15;G;while(ch>'-')z*=10,z+=ch&15,G;
59 int main(){
60     register char ch;
61     register bool fl;
62     R n,q,u,v;
63     in(n);in(q);
64     for(R i=1;i<=n;++i)s[i]=1;
65     while(q--){
66         gc;fl=ch=='A';in(u);in(v);
67         if(fl)link(u,v);
68         else{
69            makeroot(u); access(v);
70            ///题目保证x和y右边,所以我们把u换位根后,在access
71            ///  u和v一定是相邻的
72                printf("%lld
",(long long)(si[u]+1)*(si[v]+1));//可以换成上面提到的另一种
73         }
74     }
75     return 0;
76 }
原文地址:https://www.cnblogs.com/zhangbuang/p/11162832.html