Luogu3676 小清新数据结构题 动态点分治
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu3676 小清新数据结构题 动态点分治相关的知识,希望对你有一定的参考价值。
换根类型的统计问题动态点分治都是很好做的。
设所有点的点权和为$sum$
首先,我们先不考虑求$sumlimits_i s_i^2$,先考虑如何在换根的情况下求$sumlimits_i s_i$。
考虑一个点$i$会被统计多少次,显然是$dep_i+1$,那么$sumlimits_i s_i = sumlimits_i (dep_i+1) imes val_i = sumlimits_i dep_i imes val_i + sum$。
$sumlimits_i dep_i imes val_i$是不是似曾相识……其实就是幻想乡战略游戏
接着我们考虑这个烦人的平方项。那么我们还需要推一个结论:换根不会影响$W=sumlimits_i s_i imes (sum - s_i)$的值。
证明如下:
我们考虑$K = sumlimits_i sumlimits_j val_i imes val_j imes dis(i,j)$,意思就是取两个点,将中间的所有边设为两边的点的权值之积然后相加。显然这一个值是不会因为根的变化而改变的。
接着我们考虑一条边$(x,y)$对$K$的贡献,显然是这条边分割开来的两个子树的权值和的乘积,而无论根是哪一个,这两个子树中必定有且仅有一个是树的一个子树,假设$x$对应的树是子树,它就代表着$s_x imes (sum - s_x)$,把所有边的贡献加起来就是$W=sumlimits_i s_i imes (sum - s_i)=sumlimits_i sumlimits_j val_i imes val_j imes dis(i,j)$,所以$W$是不会因为根的变化而变化的。
而$W=sumlimits_i s_i imes (sum - s_i) = sum imes sumlimits_i s_i - sumlimits_i s_i^2$,那么$sumlimits_i s_i^2 = sum imes sumlimits_i s_i - W$
接着我们考虑修改点权对$W$的影响。由$Delta W = Delta v imes sumlimits_j val_j imes dep_j$,实质跟上面计算$sumlimits_i s_i$的方法一样。
1 #include<bits/stdc++.h>
2 #define int long long
3 //This code is written by Itst
4 using namespace std;
5
6 inline int read(){
7 int a = 0;
8 bool f = 0;
9 char c = getchar();
10 while(c != EOF && !isdigit(c)){
11 if(c == ‘-‘)
12 f = 1;
13 c = getchar();
14 }
15 while(c != EOF && isdigit(c)){
16 a = (a << 3) + (a << 1) + (c ^ ‘0‘);
17 c = getchar();
18 }
19 return f ? -a : a;
20 }
21
22 const int MAXN = 200010;
23 struct Edge{
24 int end , upEd;
25 }Ed[MAXN << 1];
26 int val[MAXN] , head[MAXN] , fa[MAXN][20] , dis[MAXN][20] , dep[MAXN];
27 int ST[21][MAXN << 1] , fir[MAXN] , logg2[MAXN << 1] , size[MAXN] , cur[MAXN] , up[MAXN] , sum[MAXN];
28 int cntEd , N , M , minSize , nowSize , minInd , cntST , W , allV;
29 bool vis[MAXN];
30
31 inline void addEd(int a , int b){
32 Ed[++cntEd].end = b;
33 Ed[cntEd].upEd = head[a];
34 head[a] = cntEd;
35 }
36
37 void init_dfs(int x , int p){
38 dep[x] = dep[p] + 1;
39 fir[x] = ++cntST;
40 sum[x] = val[x];
41 ST[0][cntST] = x;
42 for(int i = head[x] ; i ; i = Ed[i].upEd)
43 if(Ed[i].end != p){
44 init_dfs(Ed[i].end , x);
45 ST[0][++cntST] = x;
46 sum[x] += sum[Ed[i].end];
47 }
48 W += sum[x] * (allV - sum[x]);
49 }
50
51 inline int cmp(int a , int b){
52 return dep[a] < dep[b] ? a : b;
53 }
54
55 void init_st(){
56 for(int i = 2 ; i <= cntST ; ++i)
57 logg2[i] = logg2[i >> 1] + 1;
58 for(int i = 1 ; 1 << i <= cntST ; ++i)
59 for(int j = 1 ; j + (1 << i) - 1 <= cntST ; ++j)
60 ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
61 }
62
63 inline int LCA(int x , int y){
64 x = fir[x];
65 y = fir[y];
66 if(x > y)
67 swap(x , y);
68 int t = logg2[y - x + 1];
69 return cmp(ST[t][x] , ST[t][y - (1 << t) + 1]);
70 }
71
72 inline int calcLen(int x , int y){
73 return dep[x] + dep[y] - (dep[LCA(x , y)] << 1);
74 }
75
76 void getSize(int x){
77 vis[x] = 1;
78 ++nowSize;
79 for(int i = head[x] ; i ; i = Ed[i].upEd)
80 if(!vis[Ed[i].end])
81 getSize(Ed[i].end);
82 vis[x] = 0;
83 }
84
85 void getRoot(int x){
86 vis[x] = size[x] = 1;
87 int maxN = 0;
88 for(int i = head[x] ; i ; i = Ed[i].upEd)
89 if(!vis[Ed[i].end]){
90 getRoot(Ed[i].end);
91 maxN = max(maxN , size[Ed[i].end]);
92 size[x] += size[Ed[i].end];
93 }
94 maxN = max(maxN , nowSize - size[x]);
95 if(maxN < minSize){
96 minSize = maxN;
97 minInd = x;
98 }
99 vis[x] = 0;
100 }
101
102 void init_dfz(int x , int p){
103 nowSize = 0;
104 minSize = 0x7fffffff;
105 getSize(x);
106 getRoot(x);
107 x = minInd;
108 fa[x][0] = x;
109 fa[x][1] = p;
110 vis[x] = 1;
111 sum[x] = val[x];
112 for(int i = 1 ; fa[x][i] ; ++i){
113 fa[x][i + 1] = fa[fa[x][i]][1];
114 dis[x][i] = calcLen(fa[x][i] , x);
115 up[fa[x][i - 1]] += dis[x][i] * val[x];
116 sum[fa[x][i]] += val[x];
117 cur[fa[x][i]] += dis[x][i] * val[x];
118 }
119 for(int i = head[x] ; i ; i = Ed[i].upEd)
120 if(!vis[Ed[i].end])
121 init_dfz(Ed[i].end , x);
122 }
123
124 void init(){
125 init_dfs(1 , 0);
126 init_st();
127 init_dfz(1 , 0);
128 }
129
130 inline int query(int x){
131 int all = cur[x];
132 for(int i = 1 ; fa[x][i] ; ++i){
133 all += cur[fa[x][i]] - up[fa[x][i - 1]];
134 all += (sum[fa[x][i]] - sum[fa[x][i - 1]]) * dis[x][i];
135 }
136 return all;
137 }
138
139 inline void modify(int x , int v){
140 W += (v - val[x]) * query(x);
141 allV += v - val[x];
142 sum[x] += v - val[x];
143 for(int i = 1 ; fa[x][i] ; ++i){
144 up[fa[x][i - 1]] += (v - val[x]) * dis[x][i];
145 cur[fa[x][i]] += (v - val[x]) * dis[x][i];
146 sum[fa[x][i]] += v - val[x];
147 }
148 val[x] = v;
149 }
150
151 signed main(){
152 #ifndef ONLINE_JUDGE
153 freopen("3676.in" , "r" , stdin);
154 freopen("3676.out" , "w" , stdout);
155 #endif
156 N = read();
157 M = read();
158 for(int i = 1 ; i < N ; ++i){
159 int a = read() , b = read();
160 addEd(a , b);
161 addEd(b , a);
162 }
163 for(int i = 1 ; i <= N ; ++i){
164 val[i] = read();
165 allV += val[i];
166 }
167 init();
168 for(int i = 1 ; i <= M ; ++i)
169 if(read() == 1){
170 int x = read() , y = read();
171 modify(x , y);
172 }
173 else
174 cout << allV * (query(read()) + allV) - W << ‘
‘;
175 return 0;
176 }
以上是关于Luogu3676 小清新数据结构题 动态点分治的主要内容,如果未能解决你的问题,请参考以下文章