传送门:Problem QTREE

https://www.cnblogs.com/violet-acmer/p/9711441.html

题意:

  1. You are given a tree (an acyclic undirected connected graph,无向无环连通图) with N nodes,
  2. and edges numbered 1, 2, 3...N-1.
  3. We will ask you to perform some instructions of the following form:
  4. 有两个操作
  5. CHANGE i ti : change the cost of the i-th edge to ti(第i条边的权值变为ti
  6. or
  7. QUERY a b : ask for the maximum edge cost on the path from node a to node b
  8. (查询节点a,b间路径的最大权值)

题解:

  树链剖分模板题,看代码理解的更快;

AC代码献上:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstring>
  5. using namespace std;
  6. #define ls(x) ((x)<<1)
  7. #define rs(x) ((x)<<1 | 1)
  8. const int maxn=;
  9.  
  10. //===========链式前向星===============
  11. struct Node1
  12. {
  13. int to;
  14. int next;
  15. }edge[*maxn];
  16. int head[maxn];
  17. int cnt;
  18. void addEdge(int u,int v)
  19. {
  20. edge[cnt].to=v;
  21. edge[cnt].next=head[u];
  22. head[u]=cnt++;
  23. }
  24. //====================================
  25. //=========树链剖分用到的变量=========
  26. int fa[maxn];//fa[u] : 节点u的父节点
  27. int newId[maxn];//newId[u] : u与其父亲节点的连边在线段树中的位置
  28. int depth[maxn];//depth[u] : 节点u的深度
  29. int siz[maxn];//siz[u] : 以u为根的子树的节点数
  30. int top[maxn];//top[u] : 节点u所在的重链的顶端节点
  31. int son[maxn];//son[u] : 节点u重儿子
  32. int label;//记录newId[]中新边对应的编号
  33. //====================================
  34. //==========两次DFS()================
  35. void dfs1(int u,int f,int d) //第一遍dfs求出fa[],depth[],siz[],son[]
  36. {
  37. depth[u]=d;
  38. fa[u]=f;
  39. siz[u]=;
  40. for(int i=head[u];~i;i=edge[i].next)
  41. {
  42. int to=edge[i].to;
  43. if(to != f)
  44. {
  45. dfs1(to,u,d+);
  46. siz[u] += siz[to];
  47. if(son[u] == - || siz[to] > siz[son[u]])
  48. son[u] = to;
  49. }
  50. }
  51. }
  52. void dfs2(int u,int sp) //第二遍dfs求出top[]和newId[]
  53. {
  54. top[u]=sp;
  55. newId[u]=++label;
  56. if(son[u] == -)
  57. return ;
  58. dfs2(son[u],sp);
  59.  
  60. for(int i=head[u];~i;i=edge[i].next)
  61. {
  62. int to=edge[i].to;
  63. if(to != son[u] && to != fa[u])
  64. dfs2(to,to);
  65. }
  66. }
  67. //===================================
  68. //=============线段树================
  69. struct Node2
  70. {
  71. int l,r;
  72. int Max;
  73. int mid()
  74. {
  75. return l+((r-l)>>);
  76. }
  77. }segTree[maxn*];
  78. void buildTree(int l,int r,int pos)
  79. {
  80. segTree[pos].l = l,segTree[pos].r = r;
  81. segTree[pos].Max = ;
  82. if(l == r)
  83. return;
  84.  
  85. int mid = (l+r)/;
  86. buildTree(l,mid,ls(pos));
  87. buildTree(mid+,r,rs(pos));
  88. }
  89. void push_up(int k)//向上更新
  90. {
  91. segTree[k].Max = max(segTree[ls(k)].Max,segTree[rs(k)].Max);
  92. }
  93. void update(int k,int val,int pos) //单点更新
  94. {
  95. if(segTree[pos].l == segTree[pos].r)
  96. {
  97. segTree[pos].Max = val;
  98. return;
  99. }
  100.  
  101. int mid=segTree[pos].mid();
  102.  
  103. if(k <= mid)
  104. update(k,val,ls(pos));
  105. else
  106. update(k,val,rs(pos));
  107. push_up(pos);
  108. }
  109. int query(int l,int r,int pos)//查询线段树中[l,r]的最大值
  110. {
  111. if(segTree[pos].l == l && segTree[pos].r == r)
  112. return segTree[pos].Max;
  113.  
  114. int mid=segTree[pos].mid();
  115.  
  116. if(r <= mid)
  117. return query(l,r,ls(pos));
  118. else if(l > mid)
  119. return query(l,r,rs(pos));
  120. else
  121. return max(query(l,mid,ls(pos)),query(mid+,r,rs(pos)));
  122. }
  123. int Find(int u,int v)//查询u->v边的最大值
  124. {
  125. int res=;
  126. while(top[u] != top[v])
  127. {
  128. if(depth[top[u]] > depth[top[v]])
  129. {
  130. res=max(res,query(newId[top[u]],newId[u],));
  131. u=fa[top[u]];
  132. }
  133. else
  134. {
  135. res=max(res,query(newId[top[v]],newId[v],));
  136. v=fa[top[v]];
  137. }
  138. }
  139. if(u == v)
  140. return res;
  141. if(depth[u] > depth[v])
  142. swap(u,v);
  143. return max(res,query(newId[son[u]],newId[v],));
  144. }
  145. //===================================
  146. void Init()
  147. {
  148. cnt=;
  149. memset(head,-,sizeof(head));
  150. label=;
  151. memset(son,-,sizeof(son));
  152. }
  153. int e[maxn][];
  154. int main()
  155. {
  156. int T;
  157. scanf("%d",&T);
  158. while(T--)
  159. {
  160. int n;
  161. Init();
  162. scanf("%d",&n);
  163. for(int i=;i < n;++i)
  164. {
  165. scanf("%d%d%d",&e[i][],&e[i][],&e[i][]);
  166. addEdge(e[i][],e[i][]);
  167. addEdge(e[i][],e[i][]);
  168. }
  169. dfs1(,,);
  170. dfs2(,);
  171. buildTree(,label,);
  172. for(int i=;i < n;++i)
  173. {
  174. if(depth[e[i][]] > depth[e[i][]])
  175. swap(e[i][],e[i][]);//确保 e[i][0] 为 e[i][1]的父节点
  176. update(newId[e[i][]],e[i][],);//更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置
  177. }
  178. char op[];
  179. while(scanf("%s",op) && op[] != 'D')
  180. {
  181. int u,v;
  182. scanf("%d%d",&u,&v);
  183. if(op[] == 'Q')
  184. printf("%d\n",Find(u,v));
  185. else
  186. update(newId[e[u][]],v,);
  187. }
  188. }
  189. }

分割线:2019.5.10

省赛倒计时2天;

熟悉一下树链剖分,改改代码风格:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define ls(x) (x<<1)
  4. #define rs(x) (x<<1|1)
  5. #define mem(a,b) memset(a,b,sizeof(a))
  6. const int maxn=1e4+;
  7.  
  8. int n;///n个节点
  9. int e[maxn][];///节点e[i][0]与节点e[i][1]有条权值为e[i][2]的边
  10. int num;
  11. int head[maxn];
  12. struct Edge
  13. {
  14. int to;
  15. int next;
  16. }G[maxn<<];
  17. void addEdge(int u,int v)
  18. {
  19. G[num]=Edge{v,head[u]};
  20. head[u]=num++;
  21. }
  22. int fa[maxn];///fa[u]:节点u的父节点
  23. int tid[maxn];///tid[u]:节点u在线段树中的新编号
  24. int rid[maxn];///tid[u]=cnt,rid[cnt]=u,通过线段树中的编号查找节点
  25. int dep[maxn];///节点的深度
  26. int siz[maxn];///siz[u]:以u为根的子树的节点数
  27. int son[maxn];///son[u]:节点u重儿子
  28. int top[maxn];///top[u]:节点u所在重链的顶端节点
  29. struct Seg
  30. {
  31. int l,r;
  32. int maxVal;///区间维护最大值,根据题意而定
  33. int mid(){return l+((r-l)>>);}
  34. int len(){return r-l+;}
  35. }seg[maxn<<];
  36. void pushUp(int pos)
  37. {
  38. seg[pos].maxVal=max(seg[ls(pos)].maxVal,seg[rs(pos)].maxVal);
  39. }
  40. void buildSegTree(int l,int r,int pos)
  41. {
  42. seg[pos].l=l;
  43. seg[pos].r=r;
  44. seg[pos].maxVal=;
  45. if(l == r)
  46. return ;
  47. int mid=l+((r-l)>>);
  48. buildSegTree(l,mid,ls(pos));
  49. buildSegTree(mid+,r,rs(pos));
  50. }
  51. void Update(int l,int val,int pos)///单点更新
  52. {
  53. if(seg[pos].l == seg[pos].r)
  54. {
  55. seg[pos].maxVal=val;
  56. return ;
  57. }
  58. int mid=seg[pos].mid();
  59. if(l <= mid)
  60. Update(l,val,ls(pos));
  61. else
  62. Update(l,val,rs(pos));
  63. pushUp(pos);
  64. }
  65. int Query(int l,int r,int pos)///区间查询
  66. {
  67. if(seg[pos].l == l && seg[pos].r == r)
  68. return seg[pos].maxVal;
  69. int mid=seg[pos].mid();
  70. if(r <= mid)
  71. return Query(l,r,ls(pos));
  72. else if(l > mid)
  73. return Query(l,r,rs(pos));
  74. else
  75. return max(Query(l,mid,ls(pos)),Query(mid+,r,rs(pos)));
  76. }
  77. int Find(int u,int v)
  78. {
  79. int topU=top[u];
  80. int topV=top[v];
  81. int ans=;
  82. while(topU != topV)///u,v不在一条重链上
  83. {
  84. if(dep[topU] > dep[topV])///人为规定topU的深度低
  85. {
  86. swap(topU,topV);
  87. swap(u,v);
  88. }
  89. ans=max(ans,Query(tid[topV],tid[v],));
  90. v=fa[topV];///v来到topV的父节点所在的重链
  91. topV=top[v];
  92. }
  93. if(u == v)
  94. return ans;
  95.  
  96. if(dep[u] > dep[v])
  97. swap(u,v);
  98. return max(ans,Query(tid[son[u]],tid[v],));
  99. }
  100. void DFS1(int u,int f,int depth)///第一遍DFS求出fa,dep,siz,son
  101. {
  102. fa[u]=f;
  103. siz[u]=;
  104. dep[u]=depth;
  105. for(int i=head[u];~i;i=G[i].next)
  106. {
  107. int v=G[i].to;
  108. if(v == f)///此处是v == f才continue,在这儿出过错
  109. continue;
  110. DFS1(v,u,depth+);
  111. siz[u] += siz[v];
  112. if(son[u] == - || siz[v] > siz[son[u]])///更新重儿子
  113. son[u]=v;
  114. }
  115. }
  116. void DFS2(int u,int anc,int &k)///第二遍DFS求出tid,rid,top
  117. {
  118. top[u]=anc;
  119. tid[u]=++k;
  120. rid[k]=u;
  121. if(son[u] == -)
  122. return ;
  123. DFS2(son[u],anc,k);
  124.  
  125. for(int i=head[u];~i;i=G[i].next)
  126. {
  127. int v=G[i].to;
  128. if(v != son[u] && v != fa[u])
  129. DFS2(v,v,k);
  130. }
  131. }
  132. void Solve()
  133. {
  134. DFS1(,,);
  135. int k=;
  136. DFS2(,,k);
  137. buildSegTree(,k,);///[1,k]重新编号的节点建树
  138.  
  139. for(int i=;i < n;++i)
  140. {
  141. ///将e[i][0]与e[i][1]的边权存入儿子节点e[i][1]中
  142. if(dep[e[i][]] > dep[e[i][]])
  143. swap(e[i][],e[i][]);
  144. ///更新e[i][1]与其父节点e[i][0]的连边在线段树中的位置
  145. Update(tid[e[i][]],e[i][],);
  146. }
  147. char order[];
  148. while(~scanf("%s",order) && order[] != 'D')
  149. {
  150. int u,v;
  151. scanf("%d%d",&u,&v);
  152. if(order[] == 'Q')
  153. printf("%d\n",Find(u,v));///查询节点u,v间路径的最大值
  154. else///更新第u条边的权值,变为v,第u条边的权值信息记录在了tid[e[u][1]]中
  155. Update(tid[e[u][]],v,);
  156. }
  157. }
  158.  
  159. void Init()///初始化head,num,son
  160. {
  161. num=;
  162. mem(head,-);
  163. mem(son,-);
  164. }
  165. int main()
  166. {
  167. int test;
  168. while(~scanf("%d",&test))
  169. {
  170. while(test--)
  171. {
  172. Init();///多组输入test,Init()放在while(test--)内
  173. scanf("%d",&n);
  174. for(int i=;i < n;++i)///n-1条边
  175. {
  176. int u,v,w;
  177. scanf("%d%d%d",&u,&v,&w);
  178. e[i][]=u;
  179. e[i][]=v;
  180. e[i][]=w;
  181. addEdge(u,v);
  182. addEdge(v,u);
  183. }
  184. Solve();
  185. }
  186. }
  187. return ;
  188. }

spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)的更多相关文章

  1. Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  2. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  3. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  4. POJ3237 Tree 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...

  5. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  6. Water Tree CodeForces 343D 树链剖分+线段树

    Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...

  7. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  8. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

  9. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  10. Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组

    Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...

随机推荐

  1. Centos6.9下安装并使用VNC的操作记录

    VNC是一个的"远程桌面"工具.,通常用于“图形界面”的方式登录服务器,可视化操作.废话不多说了,操作记录如下: 1)安装桌面环境 [root@vm01 ~]# yum -y gr ...

  2. B. Divisor Subtraction

    链接 [http://codeforces.com/contest/1076/problem/B] 题意 给你一个小于1e10的n,进行下面的运算,n==0 结束,否则n-最小质因子,问你进行多少步 ...

  3. Visual Studio2013安装过程以及单元测试

    一.安装环境 操作系统版本:Windows10家庭中文版64位 CPU:i5-4200u  1.60GHz 硬盘内存:750G 二.安装版本 Visual Studio2013 三.安装过程 Visu ...

  4. 个人阅读作业WEEK7 (软件工程的瀑布, 大泥球, 教堂,集市,和银弹)

    一 . 关于银弹 (Silver Bullet) 银弹,被引申为解决问题的有效办法.IBM大型机之父福瑞德·布鲁克斯在1986年的论文<没有银弹>中表达了他的观点:软件工程中不存在银弹—— ...

  5. 2017-2018-2 1723《程序设计与数据结构》第九周作业 & 第二周结对编程 总结

    作业地址 第九次作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1878 (作业界面已评分,可随时查看,如果对自己的评分有意 ...

  6. 手工编程:hello world

    全部用命令行工具和Notepad编辑器,用手工创建并编译一个C的命令行程序:hello world. public class Hello{         public static void ma ...

  7. 现代程序设计 homework-02

    首先显示博客要求: 描述在这么多相似的需求面前, 你怎么维护你的设计 (父类/子类/基类, UML, 设计模式,  或者其它方法) 让整个程序的架构不至于崩溃的? 建议从后往前来搞,比如我通读一遍需求 ...

  8. [转帖]以Windows服务方式运行ASP.NET Core程序

    以Windows服务方式运行ASP.NET Core程序 原作者blog: https://www.cnblogs.com/guogangj/p/9198031.htmlaspnet的blog 需要持 ...

  9. Fantacy团队周一站立会议

    词频分析模型 1.首先这次站会是周一开的,但是由于我个人的疏忽,没有落实到博客上,请见谅,连累了组长. 2.会议时间:2016年3月28日12:00~12:30. 持续时长:30分钟 会议参加成员:组 ...

  10. 软件工程_2nd weeks

    本周上课没有板书,都由老师口头叙述 因此有的笔记记得不是很全,幸好有郑蕊师姐发布的课堂笔记,很好的梳理上课的内容~ 1.根据老师上课给的建议,进行了深刻的思考和反思 1.1 作为一个学硕研究生,这门课 ...