BZOJ1095 动态点分治(点分树)

忘是亡心i 2023-10-10 07:52 151阅读 0赞

题意:

操作1.修改一个点的颜色(黑白互换)

操作2.询问所有黑色点之间最远距离

点分树:当我们可以形如点分治一样的统计答案,即每次确定一个重心,然后计算他们子树之间的贡献和得出答案的时候

我们可以将每个区域的重心作为其所有子树的重心的父亲,构成一颗新的树,显然这棵树的深度不会超过logn

每次对于单点(边)更新的时候,只要对其所有的父亲更新,就只需要更新log个点,这样的数据结构就是点分树

对于本题来说,最终的答案是在每个点作为链上一个点的时候,找每个点出发的最长链和次长链的和的最大值

所以用一个堆A维护每个点在点分树中子树下所有的点到这个点父亲的距离

再用一个堆B维护每个点所有儿子点的堆A的最大值,即每条链的最长的长度

最后用一个堆C维护每个点的最长值 + 次长值的大小

tips:

1.树上两两之间的点的距离可以rmq + ST表预处理之后O(1)查询,注意转化成序列不是dfs序,具体看代码

2.做一个供删除的优先队列,可以用两个优先队列A,B,一个正常用,删除操作就是把元素加入B,当AB顶部相同的时候一起弹出

  1. #include <map>
  2. #include <set>
  3. #include <ctime>
  4. #include <cmath>
  5. #include <queue>
  6. #include <stack>
  7. #include <vector>
  8. #include <string>
  9. #include <bitset>
  10. #include <cstdio>
  11. #include <cstdlib>
  12. #include <cstring>
  13. #include <sstream>
  14. #include <iostream>
  15. #include <algorithm>
  16. #include <functional>
  17. using namespace std;
  18. #define For(i, x, y) for(int i=x;i<=y;i++)
  19. #define _For(i, x, y) for(int i=x;i>=y;i--)
  20. #define Mem(f, x) memset(f,x,sizeof(f))
  21. #define Sca(x) scanf("%d", &x)
  22. #define Sca2(x,y) scanf("%d%d",&x,&y)
  23. #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
  24. #define Scl(x) scanf("%lld",&x)
  25. #define Pri(x) printf("%d\n", x)
  26. #define Prl(x) printf("%lld\n",x)
  27. #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
  28. #define LL long long
  29. #define ULL unsigned long long
  30. #define mp make_pair
  31. #define PII pair<int,int>
  32. #define PIL pair<int,long long>
  33. #define PLL pair<long long,long long>
  34. #define pb push_back
  35. #define fi first
  36. #define se second
  37. typedef vector<int> VI;
  38. int read(){
  39. int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){
  40. if (c == '-') f = -1;c = getchar();}
  41. while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
  42. const double PI = acos(-1.0);
  43. const double eps = 1e-9;
  44. const int maxn = 2e5 + 10;
  45. const int INF = 0x3f3f3f3f;
  46. const int mod = 1e9 + 7;
  47. int N,M,K;
  48. struct heap{
  49. priority_queue<int>A,B;
  50. void push(int x){A.push(x);}
  51. void del(int x){B.push(x);}
  52. void init(){
  53. while(!B.empty() && A.top() == B.top()){
  54. A.pop(); B.pop();
  55. }
  56. }
  57. int top(){
  58. init();
  59. if(A.empty()) return 0;
  60. return A.top();
  61. }
  62. int size(){
  63. return A.size() - B.size();
  64. }
  65. int Maxdis(){
  66. if(size() < 2) return 0;
  67. int x = top(); A.pop();
  68. int y = top(); A.push(x);
  69. return x + y;
  70. }
  71. };
  72. struct Edge{
  73. int to,next;
  74. }edge[maxn << 1];
  75. int head[maxn],tot;
  76. void init(){
  77. for(int i = 0 ; i <= N ; i ++) head[i] = -1;
  78. tot = 0;
  79. }
  80. void add(int u,int v){
  81. edge[tot].to = v;
  82. edge[tot].next = head[u];
  83. head[u] = tot++;
  84. }
  85. int dep[maxn];
  86. int id[maxn],pos[maxn],cnt;
  87. void dfsinit(int u,int la){
  88. id[++cnt] = dep[u];
  89. pos[u] = cnt;
  90. for(int i = head[u]; ~i ; i = edge[i].next){
  91. int v = edge[i].to;
  92. if(v == la) continue;
  93. dep[v] = dep[u] + 1;
  94. dfsinit(v,u);
  95. id[++cnt] = dep[u];
  96. }
  97. }
  98. const int SP = 20;
  99. int MIN[maxn][SP],mm[maxn];
  100. void initRMQ(int n,int b[]){
  101. for(int i = 1; i <= n ; i ++){
  102. for(int j = 0 ; j < SP; j ++){
  103. MIN[i][j] = INF;
  104. }
  105. }
  106. mm[0] = -1;
  107. for(int i = 1; i <= n; i ++){
  108. mm[i] = ((i & (i - 1)) == 0)?mm[i - 1] + 1:mm[i - 1];
  109. MIN[i][0] = b[i];
  110. }
  111. for(int j = 1; j <= mm[n]; j ++){
  112. for(int i = 1; i + (1 << j) - 1 <= n; i ++){
  113. MIN[i][j] = min(MIN[i][j - 1],MIN[i + (1 << (j - 1))][j - 1]);
  114. }
  115. }
  116. }
  117. int rmq(int x,int y){
  118. if(x > y) swap(x,y);
  119. int k = mm[y - x + 1];
  120. return min(MIN[x][k],MIN[y - (1 << k) + 1][k]);
  121. }
  122. int getdis(int x,int y){
  123. return dep[x] + dep[y] - 2 * rmq(pos[x],pos[y]);
  124. }
  125. struct dtnode{
  126. int fa;
  127. heap Q,P;
  128. int Maxdis(){
  129. return Q.top();
  130. }
  131. int Maxline(){
  132. return P.Maxdis();
  133. }
  134. }dt[maxn];
  135. heap fans;
  136. int root,max_part,SUM;
  137. int size[maxn],vis[maxn];
  138. int dis[maxn];
  139. void dfs_root(int u,int la){
  140. size[u] = 1; int heavy = 0;
  141. for(int i = head[u]; ~i ; i = edge[i].next){
  142. int v = edge[i].to;
  143. if(v == la || vis[v]) continue;
  144. dfs_root(v,u);
  145. heavy = max(heavy,size[v]);
  146. size[u] += size[v];
  147. }
  148. if(max_part > max(heavy,SUM - heavy)){
  149. max_part = max(heavy,SUM - heavy);
  150. root = u;
  151. }
  152. }
  153. void dfs(int u,int la){
  154. dis[u] = getdis(u,dt[root].fa);
  155. dt[root].Q.push(dis[u]);
  156. for(int i = head[u]; ~i ; i = edge[i].next){
  157. int v = edge[i].to;
  158. if(v == la || vis[v]) continue;
  159. dfs(v,u);
  160. }
  161. }
  162. int divide(int t,int la){
  163. max_part = INF;
  164. root = t;
  165. dfs_root(t,-1);
  166. int now = root;
  167. dt[root].fa = la; dt[root].P.push(0);
  168. if(~la) dfs(root,-1);
  169. vis[root] = 1;
  170. for(int i = head[now]; ~i ; i = edge[i].next){
  171. int v = edge[i].to;
  172. if(vis[v]) continue;
  173. SUM = size[v];
  174. v = divide(v,now);
  175. dt[now].P.push(dt[v].Maxdis());
  176. }
  177. if(dt[now].P.size() >= 2)fans.push(dt[now].Maxline());
  178. return now;
  179. }
  180. int use[maxn];
  181. int main(){
  182. Sca(N); init();
  183. for(int i = 1; i < N ; i ++){
  184. int u = read(),v = read();
  185. add(u,v); add(v,u);
  186. }
  187. dfsinit(1,-1); initRMQ(cnt,id);
  188. SUM = N; divide(1,-1);
  189. int num = N;
  190. Sca(M);
  191. while(M--){
  192. char op[3]; scanf("%s",op);
  193. if(op[0] == 'G'){
  194. if(num == 1) puts("0");
  195. else if(!num) puts("-1");
  196. else{
  197. Pri(fans.top());
  198. }
  199. }else{
  200. int v = read(); int tmp = v;
  201. if(use[v]) num++;
  202. else num--;
  203. if(dt[v].P.size() >= 2) fans.del(dt[v].Maxline());
  204. if(use[v]) dt[v].P.push(0);
  205. else dt[v].P.del(0);
  206. if(dt[v].P.size() >= 2) fans.push(dt[v].Maxline());
  207. while(~dt[tmp].fa){
  208. int u = dt[tmp].fa;
  209. if(dt[u].P.size() >= 2) fans.del(dt[u].Maxline());
  210. if(dt[tmp].Q.size()) dt[u].P.del(dt[tmp].Maxdis());
  211. int d = getdis(v,u);
  212. if(use[v]) dt[tmp].Q.push(d);
  213. else dt[tmp].Q.del(d);
  214. if(dt[tmp].Q.size()) dt[u].P.push(dt[tmp].Maxdis());
  215. if(dt[u].P.size() >= 2) fans.push(dt[u].Maxline());
  216. tmp = u;
  217. }
  218. use[v] ^= 1;
  219. }
  220. }
  221. return 0;
  222. }

转载于:https://www.cnblogs.com/Hugh-Locke/p/11530003.html

发表评论

表情:
评论列表 (有 0 条评论,151人围观)

还没有评论,来说两句吧...

相关阅读

    相关 BZOJ1095 动态分治()

    题意: 操作1.修改一个点的颜色(黑白互换) 操作2.询问所有黑色点之间最远距离   点分树:当我们可以形如点分治一样的统计答案,即每次确定一个重心,然后计算他们子树之

    相关 分治-模板

    可能一步步克服恐惧的过程就是成功,所以只管面对恐惧,不思考结果, 24分钟敲模板,这是点分治第一次敲的这么顺利,纪念一下。 洛谷:2634.求距离是三的倍数的点对数

    相关 分治初步

      点分治是一种常用于处理树上点对关系的分治算法。   一、算法介绍   提到点分治,我们先来看一道例题:[洛谷P3806 【模板】点分治1][P3806 _1]

    相关 分治

      [传送门][Link 1](洛谷) UPDATE:关于代码中时间复杂度的更正——在代码中每一次都要通过遍历一遍询问来得到答案,所以时间复杂度是O(NMlogN), !

    相关 [笔记]分治

    基本思路:点分治,是一种针对可带权树上简单路径统计问题的算法。对于一个节点,只解决经过这棵子树的根节点的路径,对于子节点问题下推子树。 //当初的主要问题是vis[]