Description

zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。

RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。

由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。

第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。

第n+1行,有n个整数,代表所有点的初始防御值。

第n+2行一个整数 id,代表初始的首都为id。

第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

Output

对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Solution

换根板子题。

先钦定1是根dfs树剖一波,然后考虑几个操作。

链修改的操作和树形没关系,直接做。

考虑查询操作,画图以后可以发现,当一个点\(u\)不在点\(v\)的子树中时(原树上),以点\(u\)为根时\(v\)的子树形态不变。证明可以考虑此时\(u\)一定是通过\(v\)的父亲和\(v\)连接的,换根后还是通过\(v\)的父亲,而其他的子树显然还在\(u\)下方。在此不做展开。

当点\(u\)在\(v\)的子树内时,发现\(u\)和\(v\)是通过指向\(u\)的儿子链接的。于是\(u\)的那个儿子儿子所能连接到的所有点(除通过\(v\)连接的以外)都会在新树上直接作为\(u\)的子树而不是\(v\)的子树,剩下的就是\(v\)的子树了。而那个儿子能链接的所有点恰好是该儿子的子树。于是查询时查询整棵树去掉该儿子子树的min即可。

另外特判\(v\)是根的情况。直接查询子树

Code

  1. #include <cstdio>
  2. #include <algorithm>
  3. #ifdef ONLINE_JUDGE
  4. #define freopen(a, b, c)
  5. #endif
  6. #define rg register
  7. #define ci const int
  8. #define cl const long long
  9. typedef long long int ll;
  10. namespace IPT {
  11. const int L = 1000000;
  12. char buf[L], *front=buf, *end=buf;
  13. char GetChar() {
  14. if(front == end) {
  15. end = buf + fread(front = buf, 1, L, stdin);
  16. if(front == end) return -1;
  17. }
  18. return *(front++);
  19. }
  20. }
  21. template <typename T>
  22. inline void qr(T &x) {
  23. rg char ch = IPT::GetChar(), lst = ' ';
  24. while((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
  25. while((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
  26. if(lst == '-') x = -x;
  27. }
  28. template <typename T>
  29. inline void ReadDb(T &x) {
  30. rg char ch = IPT::GetChar(), lst = ' ';
  31. while((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
  32. while((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
  33. if(ch == '.') {
  34. ch = IPT::GetChar();
  35. double base = 1;
  36. while((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
  37. }
  38. if(lst == '-') x = -x;
  39. }
  40. namespace OPT {
  41. char buf[120];
  42. }
  43. template <typename T>
  44. inline void qw(T x, const char aft, const bool pt) {
  45. if(x < 0) {x = -x, putchar('-');}
  46. rg int top=0;
  47. do {OPT::buf[++top] = x % 10 + '0';} while( x /= 10);
  48. while(top) putchar(OPT::buf[top--]);
  49. if(pt) putchar(aft);
  50. }
  51. const int maxn = 100010;
  52. const int maxm = 200010;
  53. struct Edge {
  54. int to, nxt;
  55. };
  56. Edge edge[maxm]; int hd[maxn], ecnt=1;
  57. inline void cont(ci from, ci to) {
  58. Edge &e = edge[++ecnt];
  59. e.to = to; e.nxt = hd[from]; hd[from] = ecnt;
  60. }
  61. int n, m, vistime, newrot;
  62. int sz[maxn], dfn[maxn], otn[maxn], son[maxn], top[maxn], rmp[maxn], MU[maxn], deepth[maxn], fa[maxn];
  63. const int INF = (1ll << 31) - 1;
  64. struct Tree {
  65. Tree *ls, *rs;
  66. int v, tag, l, r;
  67. inline void pushup() {
  68. this->v = INF;
  69. if(this->ls) this->v = this->ls->v;
  70. if(this->rs) this->v = std::min(this->rs->v, this->v);
  71. }
  72. inline void maketag(ci _v) {
  73. this->v = _v;
  74. this->tag = _v;
  75. }
  76. inline void pushdown() {
  77. if(!this->tag) return;
  78. if(this->ls) this->ls->maketag(this->tag);
  79. if(this->rs) this->rs->maketag(this->tag);
  80. this->tag = 0;
  81. }
  82. };
  83. Tree *pool[maxm],qwq[maxm],*rot;
  84. int poltp;
  85. void reading();
  86. void dfs(ci, ci);
  87. void DFS(ci, ci);
  88. void buildpool();
  89. void buildroot();
  90. void build(Tree*, ci, ci);
  91. void change(int, int, int);
  92. void update(Tree*, ci, ci, ci);
  93. int ask(Tree*, ci, ci);
  94. int main() {
  95. freopen("1.in", "r", stdin);
  96. qr(n); qr(m);
  97. reading();
  98. qr(newrot) ;
  99. dfs(newrot, 0); DFS(newrot, newrot);
  100. buildpool(); buildroot();
  101. build(rot, 1, n);
  102. int a, b, c, d;
  103. while (m--) {
  104. a = 0; qr(a);
  105. if (a == 1) {
  106. newrot = 0; qr(newrot);
  107. } else if (a == 2) {
  108. b = c = d = 0; qr(b); qr(c); qr(d);
  109. change(b, c, d);
  110. } else if (a == 3) {
  111. a=0; qr(a);
  112. if (a == newrot) {
  113. qw(rot->v, '\n', true);
  114. } else if ((dfn[newrot] >= dfn[a]) && (dfn[newrot] <= otn[a])) {
  115. int tp = newrot;
  116. while(deepth[fa[top[tp]]] > deepth[a]) tp = fa[top[tp]];
  117. if(dfn[top[tp]] > dfn[a]) tp = top[tp];
  118. else tp = rmp[dfn[a] + 1];
  119. qw(std::min(ask(rot, 1, dfn[tp] - 1), ask(rot, otn[tp]+1, n)), '\n', true);
  120. } else {
  121. qw(ask(rot,dfn[a],otn[a]), '\n', true);
  122. }
  123. }
  124. }
  125. return 0;
  126. }
  127. void reading() {
  128. int a,b;
  129. for (rg int i = 1; i < n; ++i) {
  130. a = b = 0; qr(a); qr(b);
  131. cont(a, b); cont(b, a);
  132. }
  133. for(rg int i = 1; i <= n; ++i) qr(MU[i]);
  134. }
  135. void dfs(ci u, ci pree) {
  136. sz[u] = 1;
  137. deepth[u] = deepth[fa[u] = edge[pree].to] + 1;
  138. for (int i = hd[u]; i; i = edge[i].nxt) if (i != pree) {
  139. int &to = edge[i].to;
  140. dfs(to, i^1);
  141. if(sz[to] > sz[son[u]]) son[u] = to;
  142. }
  143. }
  144. void DFS(ci u, ci tp) {
  145. if((!u) || (dfn[u])) return;
  146. dfn[u] = ++vistime;
  147. rmp[vistime] = u;
  148. top[u] = tp;
  149. DFS(son[u], tp);
  150. for (int i = hd[u]; i; i = edge[i].nxt) {
  151. int &to = edge[i].to;
  152. if(to == son[u]) continue;
  153. DFS(to,to);
  154. }
  155. otn[u] = vistime;
  156. }
  157. void buildpool() {
  158. for (rg int i = 0; i < maxm; ++i) pool[i] = qwq+i;
  159. poltp = maxm - 1;
  160. }
  161. inline void buildroot() {
  162. rot = pool[poltp--];
  163. }
  164. void build(Tree *u, ci l, ci r) {
  165. u->l = l; u->r = r;
  166. if(l == r) {
  167. u->v = MU[rmp[l]];
  168. return;
  169. }
  170. int mid = (l + r) >> 1;
  171. if(l <= mid) {
  172. u->ls = pool[poltp--];
  173. build(u->ls, l, mid);
  174. }
  175. if(mid < r) {
  176. u->rs = pool[poltp--];
  177. build(u->rs, mid+1, r);
  178. }
  179. u->pushup();
  180. }
  181. void change(int u, int v, int p) {
  182. while(top[u] != top[v]) {
  183. if(deepth[top[u]] < deepth[top[v]]) std::swap(u, v);
  184. update(rot, dfn[top[u]], dfn[u], p);
  185. u = fa[top[u]];
  186. }
  187. if(deepth[u] < deepth[v]) std::swap(u, v);
  188. update(rot, dfn[v], dfn[u], p);
  189. }
  190. void update(Tree *u, ci l, ci r, ci v) {
  191. if((u->l > r) || (u->r < l)) return;
  192. if((u->l >= l) && (u->r <= r)) {u->maketag(v); return;}
  193. u->pushdown();
  194. if(u->ls) update(u->ls, l, r, v);
  195. if(u->rs) update(u->rs, l, r, v);
  196. u->pushup();
  197. }
  198. int ask(Tree *u, ci l, ci r) {
  199. if((u->l > r) || (u->r < l)) return INF;
  200. if((u->l >= l) && (u->r <= r)) return u->v;
  201. u->pushdown();
  202. int _ret = INF;
  203. if(u->ls) _ret = ask(u->ls, l, r);
  204. if(u->rs) _ret = std::min(ask(u->rs, l, r), _ret);
  205. return _ret;
  206. }

Summary

树上的链操作与根无关

涉及到子树的操作可以通过讨论解决。

【树链剖分换根】P3979 遥远的国度的更多相关文章

  1. 遥远的国度 (树链剖分换根),洛谷P3979

    析:显然,若没有换根操作,则为树链剖分板子题,但是这道题我们考虑换根操作 考虑这样一个性质:在一棵树上,两点的距离路径是唯一的!! 也就是说,我们在修改路径上的点权时,不必考虑根在哪里,直接利用模板修 ...

  2. [模板] dfs序, 树链剖分, 换根

    树链剖分 树链剖分是一种对树的分治, 可以把树上的任意一条链分解为 \(O(\log n)\) 条在dfs序上相邻的子链, 便于数据结构(如线段树)来维护. 另外, 子树在dfs序上也是一个连续的区间 ...

  3. 洛谷P3979 遥远的国度 树链剖分+分类讨论

    题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...

  4. 7.18 NOI模拟赛 树论 线段树 树链剖分 树的直径的中心 SG函数 换根

    LINK:树论 不愧是我认识的出题人 出的题就是牛掰 == 他好像不认识我 考试的时候 只会写42 还有两个subtask写挂了 拿了37 确实两个subtask合起来只有5分的好成绩 父亲能转移到自 ...

  5. 树链剖分(附带LCA和换根)——基于dfs序的树上优化

    .... 有点懒: 需要先理解几个概念: 1. LCA 2. 线段树(熟练,要不代码能调一天) 3. 图论的基本知识(dfs序的性质) 这大概就好了: 定义: 1.重儿子:一个点所连点树size最大的 ...

  6. BZOJ 3083: 遥远的国度 dfs序,树链剖分,倍增

    今天再做一天树的题目,明天要开始专攻图论了.做图论十几天之后再把字符串搞搞,区域赛前再把计几看看. 3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 ...

  7. BZOJ_3083_遥远的国度_树链剖分+线段树

    BZOJ_3083_遥远的国度_树链剖分 Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神Ra ...

  8. BZOJ3083 遥远的国度 【树链剖分】

    BZOJ3083 遥远的国度 Description zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcw ...

  9. BZOJ 3083 遥远的国度(树链剖分+LCA)

    Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...

随机推荐

  1. spark重点知识

    1 scala 2 spark rdd 3 sprak core 4 性能优化 5 spark sql 6 spark streaming 掌握程度-精通的理解:

  2. openstack系列文章(三)

    学习openstack的系列文章-glance glance 基本概念 glance 架构 openstack CLI Troubleshooting 1. glance 基本概念 在 opensta ...

  3. kubeadm构建k8s之Prometheus-operated监控(0.18.1)

    介绍: 大家好,k8s的搭建有许多方式,也有许多快速部署的,为了简化部署的复杂度,官方也提供了开源的kubeadm快速部署,最新1.10.x版本已经可以实现部署集群, 如果你对k8s的原理已经非常了解 ...

  4. 华为笔试——C++消重输出

    题目:消重输出 题目介绍: 输入一个正整数,给出消除重复数字以后最大的整数,注意需要考虑长整数. 例: 输入:988274320 输出:9874320 题目分析:这个结果的实现需要两个步骤:消重和排序 ...

  5. Python 并行分布式框架:Celery 超详细介绍

    本博客摘自:http://blog.csdn.net/liuxiaochen123/article/details/47981111 先来一张图,这是在网上最多的一张Celery的图了,确实描述的非常 ...

  6. Kotlin 学习笔记(一)

    (Kotlin 学习笔记的文档结构基本按照 Java 核心技术一书的目录排列) 基本程序设计结构 数据类型 数字 类型 宽度 Double 64 Float 32 Long 64 Int 32 Sho ...

  7. 冲刺ing-4

    第四次Scrum冲刺 队员完成的任务 队员 完成任务 吴伟华 Leangoo的看板截图,燃尽图 蔺皓雯 编写博客,学习后端设计 蔡晨旸 学习后端设计 曾茜 后端设计 鲁婧楠 服务器建构 杨池宇 学习后 ...

  8. 《JavaScript》JS中的跨域问题

    参考博客:https://www.cnblogs.com/yongshaoye/p/7423881.html

  9. 【技术向】rainmeter的设计与发现

    我们在大学期间所学的那点代码知识还远远不够,于是我就自己寻找到了一款简单易懂的软件,来丰富我的代码知识. 这款软件叫rainmeter,中文叫做雨滴,是一款可以修改桌面的软件.它可以将桌面上更改出硬盘 ...

  10. caffe神经网络模型的绘图

    Python/draw_net.py, 这个文件,就是用来绘制网络模型的.也就是将网络模型由prototxt变成一张图片. 1.安装GraphViz # sudo apt-get install Gr ...