题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4010

题意;

先给你一棵树,有 \(4\) 种操作:

1、如果 \(x\) 和 \(y\) 不在同一棵树上则在\(x-y\)连边.

2、如果 \(x\) 和 \(y\) 在同一棵树上并且 \(x!=y\) 则把 \(x\) 换为树根并把 \(y\) 和 \(y\) 的父亲分离.

3、如果 \(x\) 和 \(y\) 在同一棵树上则 \(x\) 到 \(y\) 的路径上所有的点权值\(+w\).

4、如果 \(x\) 和 \(y\) 在同一棵树上则输出 \(x\) 到 \(y\) 路径上的最大值.

题解:

需要支持连边和删边等操作的,一般是动态树。

先把初始化的树建好,再套个 \(LCT\) 就可以了。可以说很裸了....但要注意题目中的一些细节。然而我还是调了挺久的...

\(LCT\) 的基本操作复杂度均摊是\(O(log^2n)\),不过常数可能大一点。

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. // 动态树问题,即要求我们维护一个由若干棵子结点无序的有根树组成的森林的连通性问题。
  5. // 要求这个数据结构支持对树的分割、合并,对某个点到它到根的路径的某些操作
  6. // LCT的基本操作复杂度为均摊O(log^2n).
  7. // http://acm.hdu.edu.cn/showproblem.php?pid=4010
  8. const int N = 300100;
  9. int n,m,val[N];
  10. struct Link_Cut_Tree
  11. {
  12. int top,son[N][2],fa[N],q[N],rev[N];
  13. int NodeVal[N]; // 每个点的权值
  14. int MAX[N];
  15. int ADD[N];
  16. void init()
  17. {
  18. for(int i=0;i<=n;i++) {
  19. son[i][0] = son[i][1] = 0;
  20. }
  21. top = 0;
  22. memset(son,0,sizeof(son));
  23. memset(fa,0,sizeof(fa));
  24. memset(q,0,sizeof(q));
  25. memset(rev,0,sizeof(rev));
  26. memset(NodeVal,0,sizeof(NodeVal));
  27. memset(MAX,0,sizeof(MAX));
  28. memset(ADD,0,sizeof(ADD));
  29. }
  30. inline void pushup(int x) //上传Splay的最大值
  31. {
  32. MAX[x] = max(MAX[son[x][0]],MAX[son[x][1]]);
  33. MAX[x] = max(MAX[x],NodeVal[x]);
  34. }
  35. void add(int x, int v)
  36. {
  37. NodeVal[x] += v;
  38. MAX[x] += v;
  39. ADD[x] += v;
  40. }
  41. inline void pushdown(int x) //下放Splay的翻转标记
  42. {
  43. int l=son[x][0],r=son[x][1];
  44. if(rev[x]){
  45. rev[l]^=1;rev[r]^=1;rev[x]^=1;
  46. swap(son[x][0],son[x][1]);
  47. }
  48. if(ADD[x])
  49. {
  50. if(son[x][0]) {
  51. add(son[x][0],ADD[x]);
  52. }
  53. if(son[x][1]) {
  54. add(son[x][1],ADD[x]);
  55. }
  56. ADD[x] = 0;
  57. }
  58. }
  59. // 判断这是不是一条重路径的根,只要他的fa指针指向的节点的左右子树都不是他,
  60. // 证明此时这是一条虚边那么这就是一棵子树的根节点
  61. inline bool isroot(int x) {
  62. return !fa[x] || (son[fa[x]][0]!=x && son[fa[x]][1]!=x);
  63. }
  64. void rotate(int x) {
  65. int y=fa[x],z=fa[y],l,r;
  66. if(son[y][0]==x)l=0;
  67. else l=1;
  68. r=l^1;
  69. if(!isroot(y)) {
  70. if(son[z][0]==y) son[z][0]=x;
  71. else son[z][1]=x;
  72. }
  73. fa[x]=z; fa[y]=x;
  74. fa[son[x][r]]=y;
  75. son[y][l]=son[x][r]; son[x][r]=y;
  76. pushup(y); pushup(x);
  77. }
  78. // 提根
  79. void splay(int x) {
  80. top=1;q[top]=x;
  81. for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
  82. for(int i=top;i;i--) pushdown(q[i]);
  83. while(!isroot(x)) {
  84. int y=fa[x],z=fa[y];
  85. if(!isroot(y)) {
  86. if((son[y][0]==x)^(son[z][0]==y)) rotate(x);
  87. else rotate(y);
  88. }
  89. rotate(x);
  90. }
  91. }
  92. // LCT核心:从当前的节点x向它所在的根节点连一条重路径,相当于把沿路的重路径全都断开,重新拉一条从x到根的重路径
  93. void access(int x) {
  94. for(int t=0;x;t=x,x=fa[x]) {
  95. splay(x);
  96. son[x][1]=t;
  97. pushup(x);
  98. }
  99. }
  100. //换根:让 x 成为当前树的根节点
  101. void makeroot(int x) {
  102. access(x);
  103. splay(x);
  104. rev[x]^=1;
  105. }
  106. // 先找到 x 所在的 auxiliary tree(即preferred path),并查找返回该条路径最小的节点(即根)
  107. int find_root(int x) {
  108. access(x);
  109. splay(x);
  110. while(son[x][0]) x=son[x][0];
  111. return x;
  112. }
  113. //获取到 x−y所对应的路径,可以通过访问y节点来获取到有关路径的信息
  114. void split(int x,int y) {
  115. makeroot(x);
  116. access(y);
  117. splay(y);
  118. }
  119. // 断开 x 和 y 之间的边
  120. void cut(int x,int y) {
  121. split(x,y);
  122. // if(son[y][0]==x && son[x][1]==0)
  123. // {
  124. // son[y][0]=0, fa[x]=0;
  125. // pushup(y);
  126. // }
  127. fa[son[y][0]]=0;son[y][0]=0;
  128. pushup(y);
  129. }
  130. // 在 x 和 y 之间连边
  131. void link(int x,int y) {
  132. makeroot(x);
  133. // 注意有些题不保证x,y未联通,还需要判断一下联通性
  134. // if(find_root(y)==x) return; //两点已经在同一子树中,再连边不合法
  135. fa[x]=y;
  136. }
  137. // 将x-y路径上的权值都加 w
  138. void add_val(int x,int y,int w)
  139. {
  140. split(x,y);
  141. add(y,w);
  142. }
  143. // 输出x-y之间的最大点权
  144. int query(int x, int y)
  145. {
  146. split(x,y);
  147. return MAX[y];
  148. }
  149. }LCT;
  150. std::vector<int> ve[N];
  151. void dfs(int u, int fa)
  152. {
  153. LCT.fa[u] = fa;
  154. for(int i = 0; i < (int)ve[u].size(); i++){
  155. int v = ve[u][i];
  156. if(v == fa)continue;
  157. dfs(v,u);
  158. }
  159. }
  160. int main(int argc, char const *argv[]) {
  161. // freopen("in.txt","r",stdin);
  162. while(std::cin >> n) {
  163. memset(val,0,sizeof(val));
  164. for(int i = 0; i <= n; i++) ve[i].clear();
  165. LCT.init();
  166. for(int i = 1; i < n; i++) {
  167. int u,v;
  168. scanf("%d%d",&u,&v);
  169. // LCT.link(u,v);
  170. ve[u].push_back(v);
  171. ve[v].push_back(u);
  172. }
  173. dfs(1,0);
  174. for(int i = 1; i <= n; i++) {
  175. int x;
  176. scanf("%d", &x);
  177. LCT.NodeVal[i] = x;
  178. LCT.MAX[i] = x;
  179. }
  180. std::cin >> m;
  181. for(int i = 1; i <= m; i++) {
  182. int op, x, y;
  183. scanf("%d", &op);
  184. // 连接x到 y,若x到 y已经联通则无需连接
  185. if(op == 1) {
  186. scanf("%d%d",&x,&y);
  187. int xx = LCT.find_root(x), yy = LCT.find_root(y);
  188. if(xx != yy) LCT.link(x,y);
  189. else {
  190. puts("-1");
  191. }
  192. }
  193. // 删除边(x,y),但不保证边(x,y)存在
  194. else if(op == 2)
  195. {
  196. scanf("%d%d",&x,&y);
  197. int xx = LCT.find_root(x), yy = LCT.find_root(y);
  198. if(xx == yy && x != y) LCT.cut(x,y);
  199. else {
  200. puts("-1");
  201. }
  202. }
  203. // 将x-y路径上的权值都加 w
  204. else if(op == 3) {
  205. int w;
  206. scanf("%d%d%d",&w,&x,&y);
  207. // std::cout << "w = " << w << '\n';
  208. if(LCT.find_root(x) == LCT.find_root(y)) LCT.add_val(x,y,w);
  209. else puts("-1");
  210. }
  211. // 输出x-y之间的最大点权
  212. else if(op == 4) {
  213. scanf("%d%d",&x,&y);
  214. if(LCT.find_root(x) == LCT.find_root(y)) printf("%d\n",LCT.query(x,y));
  215. else {
  216. puts("-1");
  217. }
  218. }
  219. }
  220. puts("");
  221. }
  222. return 0;
  223. }

HDU 4010 Query on The Trees (动态树)(Link-Cut-Tree)的更多相关文章

  1. HDU 4010 Query on The Trees(动态树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4010 题意:一棵树,四种操作: (1)若x和y不在一棵树上,将x和y连边: (2)若x和y在一棵树上, ...

  2. 动态树(Link Cut Tree) :SPOJ 375 Query on a tree

    QTREE - Query on a tree #number-theory You are given a tree (an acyclic undirected connected graph) ...

  3. 动态树(LCT):HDU 4010 Query on The Trees

    Query on The Trees Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Othe ...

  4. HDU 4010.Query on The Trees 解题报告

    题意: 给出一颗树,有4种操作: 1.如果x和y不在同一棵树上则在xy连边 2.如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离 3.如果x和y在同一棵树上则x到y的路径上所有的点 ...

  5. HDU 4010 Query on The Trees(动态树LCT)

    Problem Description We have met so many problems on the tree, so today we will have a query problem ...

  6. HDU 4010 Query on The Trees(动态树)

    题意 给定一棵 \(n\) 个节点的树,每个点有点权.完成 \(m\) 个操作,操作四两种,连接 \((x,y)\) :提 \(x\) 为根,并断 \(y\) 与它的父节点:增加路径 \((x,y)\ ...

  7. HDU 4010 Query on The Trees

    Problem Description We have met so many problems on the tree, so today we will have a query problem ...

  8. hdu 4010 Query on The Trees LCT

    支持:1.添加边 x,y2.删边 x,y3.对于路径x,y上的所有节点的值加上w4.询问路径x,y上的所有节点的最大权值 分析:裸的lct...rev忘了清零死循环了两小时... 1:就是link操作 ...

  9. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

随机推荐

  1. 【codeforces 538E】Demiurges Play Again

    [题目链接]:http://codeforces.com/problemset/problem/538/E [题意] 给你一棵树; 有两个人,分别从根节点开始,往叶子节点的方向走; 每个人每次只能走一 ...

  2. java教程(五)SSH框架-配置

    前言:从这篇博客開始我将继续讲述Java教程:SSH篇.主要内容环绕SSH框架分析与搭建,今天先简介一下SSH的配置. SSH配置顺序是: spring-->hibernate-->str ...

  3. 智课雅思短语---一、be no exception

    智课雅思短语---一.be no exception 一.总结 一句话总结:…也不例外? …be no exception 1.经济的快速发展? the rapid development of ec ...

  4. c# 读取导入的excel文件,循环批量处理数据

    dt = FM_HR_ShiftMaintenanceManager.GetCsvToDataTable(strConn, excelName,"XJSQMonthlyImportExcel ...

  5. Network Stack‎ : Disk Cache

    Disk Cache 目录 1 Overview 2 External Interface 3 Disk Structure 3.1 Cache Address 3.2 Index File Stru ...

  6. 利用反射实现Servlet公共类的抽取

    一次请求的执行过程: 请求:发送请求地址-->到达web.xml中,找到地址对应的servlet类-->通过反射调用该类的构造函数,创建该servlet类的对象-->通过当前对象调用 ...

  7. 今日SGU 5.20

    SGU 404 题意:.. 收获:取模 #include<bits/stdc++.h> #define de(x) cout<<#x<<"="& ...

  8. 数据库更新DATE类型的时间

    使用to_date() 进行格式转换 to_date('2018/11/16','yyyy/MM/dd') update tableName t set t.shipment_date = to_da ...

  9. CCF模拟题 相反数

    相反数 时间限制: 1.0s 内存限制: 256.0MB 问题描述 有 N 个非零且各不相同的整数.请你编一个程序求出它们中有多少对相反数(a 和 -a 为一对相反数).   输入格式 第一行包含一个 ...

  10. CF 439C(251C题)Devu and Partitioning of the Array

    Devu and Partitioning of the Array time limit per test 1 second memory limit per test 256 megabytes ...