题意:写一个数据结构,支持森林上:连边、删边、翻转点的颜色(黑白)、查询以某一点为根的某棵树上所有黑色点到根的距离和。$\text{点数} \leq 10^5 , \text{操作数} \leq 3 \times 10^5$
连边删边不用说就是$LCT$,而边有边权,显然需要化边为点进行操作
考虑如何维护最后一个信息。考虑$LCT$中$Splay$上的某一棵子树,$Splay$的根为$x$,其左子树为$lson$,右子树为$rson$,虚子树统一称为$son$
如果我们已经计算好了$lson,rson,son$的答案,如何计算$x$的答案?
因为$Splay$上对应原树的一条链,所以:
①$rson$与$son$中的黑点在需要经过左子树中的所有边和$x$(如果$x$代表一条边),所以答案需要加上$rson$与$son$中的黑点总数$\times\,$($x$代表的边的边权$+lson$中的实链边权总和)
②如果$x$代表一个黑点,它需要经过左子树中的所有边,所以答案需要加上$lson$中的实链边权总和
③答案再加上$lson,rson,son$的答案即可。
所以我们需要维护子树的边权总和、黑点总数,才能够计算答案。
需要注意以下几点:
①边权总和不需要将虚子树的计算在内(显然虚子树内的点都在虚子树上传的时候计算完了答案,所以在其他点上不会产生贡献),只需要把实链的计算上去
②因为需要$makeroot$操作,所以你还要记录将左右子树反过来之后的答案,这样才能正确下传标记
③注意一点:翻转左右子树对虚子树内部答案没有影响,所以虚子树答案直接上传不经过翻转的即可
1 #include<bits/stdc++.h> 2 #define lch Tree[x].ch[0] 3 #define rch Tree[x].ch[1] 4 #define int long long 5 //This code is written by Itst 6 using namespace std; 7 8 inline int read(){ 9 int a = 0; 10 bool f = 0; 11 char c = getchar(); 12 while(c != EOF && !isdigit(c)){ 13 if(c == '-') 14 f = 1; 15 c = getchar(); 16 } 17 while(c != EOF && isdigit(c)){ 18 a = (a << 3) + (a << 1) + (c ^ '0'); 19 c = getchar(); 20 } 21 return f ? -a : a; 22 } 23 24 const int MAXN = 100010; 25 struct node{ 26 int fa , ch[2] , size , non_size; 27 long long val , sumE , sumL , non_sum , sumR; 28 bool mark , col; 29 }Tree[MAXN << 2]; 30 int N , M , K , cntNode; 31 32 inline bool nroot(int x){ 33 return Tree[Tree[x].fa].ch[0] == x || Tree[Tree[x].fa].ch[1] == x; 34 } 35 36 inline bool son(int x){ 37 return Tree[Tree[x].fa].ch[1] == x; 38 } 39 40 inline void pushup(int x){ 41 Tree[x].size = Tree[lch].size + Tree[rch].size + Tree[x].non_size + Tree[x].col; 42 Tree[x].sumE = Tree[lch].sumE + Tree[rch].sumE + Tree[x].val; 43 Tree[x].sumL = Tree[lch].sumL + Tree[rch].sumL + Tree[x].non_sum +(Tree[rch].size + Tree[x].non_size + Tree[x].col) * (Tree[x].val + Tree[lch].sumE); 44 Tree[x].sumR = Tree[lch].sumR + Tree[rch].sumR + Tree[x].non_sum + (Tree[lch].size + Tree[x].non_size + Tree[x].col) * (Tree[x].val + Tree[rch].sumE); 45 } 46 47 inline void rotate(int x){ 48 bool f = son(x); 49 int y = Tree[x].fa , z = Tree[y].fa , w = Tree[x].ch[f ^ 1]; 50 if(nroot(y)) 51 Tree[z].ch[son(y)] = x; 52 Tree[x].fa = z; 53 Tree[x].ch[f ^ 1] = y; 54 Tree[y].fa = x; 55 Tree[y].ch[f] = w; 56 if(w) 57 Tree[w].fa = y; 58 pushup(y); 59 } 60 61 inline void reverse(int x){ 62 Tree[x].mark ^= 1; 63 swap(lch , rch); 64 swap(Tree[x].sumL , Tree[x].sumR); 65 } 66 67 inline void pushdown(int x){ 68 if(Tree[x].mark){ 69 reverse(lch); 70 reverse(rch); 71 Tree[x].mark = 0; 72 } 73 } 74 75 void pushdown_all(int x){ 76 if(nroot(x)) 77 pushdown_all(Tree[x].fa); 78 pushdown(x); 79 } 80 81 inline void Splay(int x){ 82 pushdown_all(x); 83 while(nroot(x)){ 84 if(nroot(Tree[x].fa)) 85 rotate(son(Tree[x].fa) == son(x) ? Tree[x].fa : x); 86 rotate(x); 87 } 88 pushup(x); 89 } 90 91 inline void access(int x){ 92 for(int y = 0 ; x ; y = x , x = Tree[x].fa){ 93 Splay(x); 94 Tree[x].non_size = Tree[x].non_size + Tree[Tree[x].ch[1]].size - Tree[y].size; 95 Tree[x].non_sum = Tree[x].non_sum + Tree[Tree[x].ch[1]].sumL - Tree[y].sumL; 96 Tree[x].ch[1] = y; 97 pushup(x); 98 } 99 } 100 101 inline void makeroot(int x){ 102 access(x); 103 Splay(x); 104 reverse(x); 105 } 106 107 inline void split(int x , int y){ 108 makeroot(x); 109 access(y); 110 Splay(y); 111 } 112 113 inline void _link(int x , int y){ 114 makeroot(x); 115 makeroot(y); 116 Tree[y].non_size += Tree[x].size; 117 Tree[y].non_sum += Tree[x].sumL; 118 Tree[x].fa = y; 119 pushup(y); 120 } 121 122 inline void link(int x , int y , int val){ 123 Tree[++cntNode].val = val; 124 _link(x , cntNode); 125 _link(y , cntNode); 126 } 127 128 inline void cut(int x , int y){ 129 split(y , x); 130 if(Tree[y].fa == x){ 131 Tree[y].ch[1] = 0; 132 pushup(y); 133 } 134 else 135 Tree[y].fa = Tree[Tree[y].fa].ch[0] = 0; 136 lch = Tree[lch].fa = 0; 137 pushup(x); 138 } 139 140 inline void query(int x){ 141 makeroot(x); 142 printf("%lld\n" , Tree[x].sumL); 143 } 144 145 inline char getc(){ 146 char c = getchar(); 147 while(!isupper(c)) 148 c = getchar(); 149 return c; 150 } 151 152 signed main(){ 153 #ifndef ONLINE_JUDGE 154 freopen("558.in" , "r" , stdin); 155 freopen("558.out" , "w" , stdout); 156 #endif 157 N = read(); 158 M = read(); 159 K = read(); 160 cntNode = N; 161 int a , b , w; 162 while(M--){ 163 a = read(); 164 b = read(); 165 w = read(); 166 link(a , b , w); 167 } 168 while(K--) 169 switch(getc()){ 170 case 'L': 171 a = read(); 172 b = read(); 173 w = read(); 174 link(a , b , w); 175 break; 176 case 'C': 177 a = read(); 178 b = read(); 179 cut(a , b); 180 break; 181 case 'F': 182 a = read(); 183 makeroot(a); 184 Tree[a].col ^= 1; 185 pushup(a); 186 break; 187 case 'Q': 188 query(read()); 189 break; 190 } 191 return 0; 192 }