题解

一眼就是线段树维护点分树的dfs序嘛

代码debug一年(手动再见)

码力直线下降,坐等滚粗= =

很明显的我们需要一个点分树,然后求出以每个重心为根的树的dfs序,线段树维护一下每个点的价值-每个点到根的距离

对于修改点直接单点修改,对于边相当于修改了一个子树到根的距离,就是dfs序上一段区间的加减

然后查询点分树里除掉这个点所在子树的区间,查询两边区间的最大值即可

代码

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <cstdio>
  4. #include <cstring>
  5. #include <queue>
  6. #define enter putchar('\n')
  7. #define space putchar(' ')
  8. #define MAXN 100005
  9. #define mp make_pair
  10. #define pb push_back
  11. #define fi first
  12. #define se second
  13. //#define ivorysi
  14. using namespace std;
  15. typedef long long int64;
  16. template<class T>
  17. void read(T &res) {
  18. res = 0;char c = getchar();T f = 1;
  19. while(c < '0' || c > '9') {
  20. if(c == '-') f = -1;
  21. c = getchar();
  22. }
  23. while(c >= '0' && c <= '9') {
  24. res = res * 10 + c - '0';
  25. c = getchar();
  26. }
  27. res *= f;
  28. }
  29. template<class T>
  30. void out(T x) {
  31. if(x < 0) {putchar('-');x = -x;}
  32. if(x >= 10) {
  33. out(x / 10);
  34. }
  35. putchar('0' + x % 10);
  36. }
  37. int Line[MAXN],idx;
  38. int64 D[MAXN];
  39. pair<int64,int> Max(pair<int64,int> a,pair<int64,int> b) {
  40. if(a.fi != b.fi) return a.fi < b.fi ? b : a;
  41. else return a.se < b.se ? a : b;
  42. }
  43. struct Segment_Tree {
  44. struct Tr_node {
  45. int L,R,lc,rc;
  46. int64 lazy;
  47. pair<int64,int> S;
  48. }tr[MAXN * 40];
  49. int Ncnt;
  50. #define lc(u) tr[u].lc
  51. #define rc(u) tr[u].rc
  52. void update(int u) {
  53. tr[u].S = Max(tr[lc(u)].S,tr[rc(u)].S);
  54. }
  55. void addlazy(int u,int64 v) {
  56. tr[u].S.fi += v;
  57. tr[u].lazy += v;
  58. }
  59. void pushdown(int u) {
  60. if(tr[u].lazy) {
  61. addlazy(lc(u),tr[u].lazy);
  62. addlazy(rc(u),tr[u].lazy);
  63. tr[u].lazy = 0;
  64. }
  65. }
  66. void build(int &u,int L,int R) {
  67. u = ++Ncnt;
  68. tr[u].L = L;tr[u].R = R;
  69. if(L == R) {
  70. tr[u].S = mp(D[Line[L]],Line[L]);
  71. return;
  72. }
  73. int mid = (L + R) >> 1;
  74. build(tr[u].lc,L,mid);
  75. build(tr[u].rc,mid + 1,R);
  76. update(u);
  77. }
  78. void Add(int u,int l,int r,int64 v) {
  79. if(tr[u].L == l && tr[u].R == r) {addlazy(u,v);return;}
  80. int mid = (tr[u].L + tr[u].R) >> 1;
  81. pushdown(u);
  82. if(r <= mid) Add(lc(u),l,r,v);
  83. else if(l > mid) Add(rc(u),l,r,v);
  84. else {Add(lc(u),l,mid,v),Add(rc(u),mid + 1,r,v);}
  85. update(u);
  86. }
  87. pair<int64,int> Query(int u,int l,int r) {
  88. if(r < l) return mp(-1e18,-1);
  89. if(tr[u].L == l && tr[u].R == r) return tr[u].S;
  90. pushdown(u);
  91. int mid = (tr[u].L + tr[u].R) >> 1;
  92. if(r <= mid) return Query(lc(u),l,r);
  93. else if(l > mid) return Query(rc(u),l,r);
  94. else return Max(Query(lc(u),l,mid),Query(rc(u),mid + 1,r));
  95. }
  96. }SegTr;
  97. struct node {
  98. int to,next;int64 val;
  99. }E[MAXN * 2];
  100. int head[MAXN],sumE;
  101. void add(int u,int v,int64 c) {
  102. E[++sumE].to = v;
  103. E[sumE].next = head[u];
  104. E[sumE].val = c;
  105. head[u] = sumE;
  106. }
  107. struct PointDivideTree {
  108. vector<int> Fa,dfn,aux,siz;
  109. vector<int64> Fa_dis;
  110. int rt;
  111. }PD[MAXN];
  112. int N,Q;
  113. int64 z[MAXN];
  114. bool vis[MAXN];
  115. int siz[MAXN],son[MAXN],fa[MAXN];
  116. int que[MAXN],ql,qr;
  117. int calcG(int st) {
  118. ql = 1,qr = 0;
  119. que[++qr] = st;fa[st] = 0;
  120. while(ql <= qr) {
  121. int u = que[ql++];
  122. siz[u] = 1;son[u] = 0;
  123. for(int i = head[u] ; i ; i = E[i].next) {
  124. int v = E[i].to;
  125. if(!vis[v] && fa[u] != v) {
  126. fa[v] = u;
  127. que[++qr] = v;
  128. }
  129. }
  130. }
  131. int res = que[qr];
  132. for(int i = qr ; i >= 1 ; --i) {
  133. int u = que[i];
  134. son[u] = max(son[u],qr - siz[u]);
  135. if(son[u] < son[res]) res = u;
  136. siz[fa[u]] += siz[u];
  137. if(siz[u] > son[fa[u]]) son[fa[u]] = siz[u];
  138. }
  139. return res;
  140. }
  141. int Calc(int u,int fa,int64 fa_dis,int G) {
  142. int s = 1;
  143. ++idx;
  144. Line[idx] = u;
  145. D[u] = D[fa] + fa_dis;
  146. PD[u].aux.pb(G);
  147. PD[u].Fa.pb(fa);
  148. PD[u].dfn.pb(idx);
  149. PD[u].Fa_dis.pb(fa_dis);
  150. for(int i = head[u] ; i ; i = E[i].next) {
  151. int v = E[i].to;
  152. if(!vis[v] && v != fa) {
  153. s += Calc(v,u,E[i].val,G);
  154. }
  155. }
  156. PD[u].siz.pb(s);
  157. return s;
  158. }
  159. void pre(int u) {
  160. int G = calcG(u);
  161. vis[G] = 1;
  162. idx = 0;D[G] = 0;
  163. Calc(G,0,0,G);
  164. for(int i = 1 ; i <= idx ; ++i) D[Line[i]] = z[Line[i]] - D[Line[i]];
  165. SegTr.build(PD[G].rt,1,idx);
  166. for(int i = head[G] ; i ; i = E[i].next) {
  167. int v = E[i].to;
  168. if(!vis[v]) pre(v);
  169. }
  170. }
  171. void Init() {
  172. read(N);read(Q);
  173. for(int i = 1 ; i <= N ; ++i) read(z[i]);
  174. int u,v;int64 c;
  175. for(int i = 1 ; i < N ; ++i) {
  176. read(u);read(v);read(c);
  177. add(u,v,c);add(v,u,c);
  178. }
  179. pre(1);
  180. }
  181. void Solve() {
  182. int op,u,v;
  183. int64 w;
  184. int st = 1;
  185. for(int q = 1 ; q <= Q ; ++q) {
  186. read(op);
  187. if(op == 1) {
  188. read(u);read(w);
  189. int s = PD[u].aux.size();
  190. for(int i = 0 ; i < s ; ++i) {
  191. int G = PD[u].aux[i];
  192. SegTr.Add(PD[G].rt,PD[u].dfn[i],PD[u].dfn[i],w - z[u]);
  193. }
  194. z[u] = w;
  195. }
  196. else {
  197. read(u);read(v);read(w);
  198. int s = min(PD[u].aux.size(),PD[v].aux.size());
  199. for(int i = 0 ; i < s ; ++i) {
  200. int rt = PD[PD[u].aux[i]].rt;
  201. if(PD[u].Fa[i] == v) {
  202. SegTr.Add(rt,PD[u].dfn[i],PD[u].dfn[i] + PD[u].siz[i] - 1,PD[u].Fa_dis[i] - w);
  203. PD[u].Fa_dis[i] = w;
  204. }
  205. else if(PD[v].Fa[i] == u) {
  206. SegTr.Add(rt,PD[v].dfn[i],PD[v].dfn[i] + PD[v].siz[i] - 1,PD[v].Fa_dis[i] - w);
  207. PD[v].Fa_dis[i] = w;
  208. }
  209. else break;
  210. }
  211. }
  212. pair<int64,int> p = mp(-1e18,-1);
  213. int s = PD[st].aux.size();
  214. for(int i = 0 ; i < s; ++i) {
  215. int G = PD[st].aux[i],rt = PD[G].rt;
  216. int64 t = -SegTr.Query(rt,PD[st].dfn[i],PD[st].dfn[i]).fi + z[st];
  217. pair<int64,int> k;
  218. if(i != s - 1) k = Max(SegTr.Query(rt,1,PD[st].dfn[i] - 1),SegTr.Query(rt,PD[st].dfn[i] + PD[st].siz[i],PD[G].siz[i]));
  219. else k = SegTr.Query(rt,2,PD[G].siz[i]);
  220. if(k.se == -1) continue;
  221. p = Max(p,mp(k.fi - t,k.se));
  222. }
  223. st = p.se;
  224. out(st);space;
  225. }
  226. }
  227. int main() {
  228. #ifdef ivorysi
  229. freopen("f1.in","r",stdin);
  230. #endif
  231. Init();
  232. Solve();
  233. }

【LOJ】#2497. 「PA 2017」Banany的更多相关文章

  1. 【LOJ】#2290. 「THUWC 2017」随机二分图

    题解 看了一眼觉得是求出图对图统计完美匹配的个数(可能之前做过这样模拟题弃疗了,一直心怀恐惧... 然后说是统计一下每种匹配出现的概率,也就是,当前左边点匹配状态为S,右边点匹配状态为T,每种匹配出现 ...

  2. 【LOJ】#2289. 「THUWC 2017」在美妙的数学王国中畅游

    题解 我们发现,题目告诉我们这个东西就是一个lct 首先,如果只有3,问题就非常简单了,我们算出所有a的总和,所有b的总和就好了 要是1和2也是多项式就好了--其实可以!也就是下面泰勒展开的用处,我们 ...

  3. 【LOJ】#3088. 「GXOI / GZOI2019」旧词

    LOJ#3088. 「GXOI / GZOI2019」旧词 不懂啊5e4感觉有点小 就是离线询问,在每个x上挂上y的询问 然后树剖,每个节点维护轻儿子中已经被加入的点的个数个数乘上\(dep[u]^{ ...

  4. 【LOJ】#3087. 「GXOI / GZOI2019」旅行者

    LOJ#3087. 「GXOI / GZOI2019」旅行者 正着求一遍dij,反着求一遍,然后枚举每条边,从u到v,如果到u最近的点和v能到的最近的点不同,那么可以更新答案 没了 #include ...

  5. 【LOJ】#3086. 「GXOI / GZOI2019」逼死强迫症

    LOJ#3086. 「GXOI / GZOI2019」逼死强迫症 这个就是设状态为\(S,j\)表示轮廓线为\(S\),然后用的1×1个数为j 列出矩阵转移 这样会算重两个边相邻的,只要算出斐波那契数 ...

  6. 【LOJ】#3085. 「GXOI / GZOI2019」特技飞行

    LOJ#3085. 「GXOI / GZOI2019」特技飞行 这显然是两道题,求\(C\)是一个曼哈顿转切比雪夫后的线段树扫描线 求\(AB\),对向交换最大化和擦身而过最大化一定分别为最大值和最小 ...

  7. 【LOJ】#3083. 「GXOI / GZOI2019」与或和

    LOJ#3083. 「GXOI / GZOI2019」与或和 显然是先拆位,AND的答案是所有数字为1的子矩阵的个数 OR是所有的子矩阵个数减去所有数字为0的子矩阵的个数 子矩阵怎么求可以记录每个位置 ...

  8. 【LOJ】#2349. 「JOI 2017/2018 决赛」团子制作

    题解 有意思的一个dp,我们对G计数,发现如果不在同一条对角线上的G肯定不会互相影响,所以我们对于每一条对角线dp dp的方式是枚举这个G以什么方式放,横着还是竖着,还是不放 代码 #include ...

  9. 【LOJ】#2350. 「JOI 2017/2018 决赛」月票购买

    题解 首先求一个最短路图出来,最短路图就是这条边在最短路上就保留,否则就不保留,注意最短路图是一个有向图,一条边被保留的条件是 dis(S,u) + val(u,v) = dis(v,T)我们需要求两 ...

随机推荐

  1. gitlab的备份与恢复与迁移

    一.gitlab的备份1.1 创建备份目录,并授权 1 2 3 4 [root@linux-node1 ~]# mkdir /data/backups/gitlab -p [root@linux-no ...

  2. 转:iOS-CoreLocation:无论你在哪里,我都要找到你!

    1.定位 使用步骤: 创建CLLocationManager示例,并且需要强引用它 设置CLLocationManager的代理,监听并获取所更新的位置 启动位置更新 1 2 3 _manager = ...

  3. 转:Xcode 删除文件后编译出现的missing file的警告

    进入“Missing File”对应的目录进行删除即可. 1.由于使用SVN导致的,可进行如下操作: # cd ~/iHost/Demo/sfsimonutility/SFSimonUtility/S ...

  4. Linux Shell管道调用用户定义函数(使shell支持map函数式特性)

    Linux中有一个管道的概念,常用来流式的处理文本内容,比如一个文件对其中的每一行应用好几个操作,出于两个方面的考虑可能需要在管道中使用用户定义函数: 1. 刚需: 内置的sed/awk之类的可能没法 ...

  5. spring-boot-CommandLineRunner

    在项目服务启动完成后就去加载一些数据 @Component public class MyStartupRunner1 implements CommandLineRunner { @Override ...

  6. oracle关键字作为字段名使用方法

    有时我们在定义字段名及别名时所用名与oracle关键字同名,这时该如何处理呢? 其实很简单,只要在此关键字加上"",如"group" SQL> DROP ...

  7. css给表格每一列设置不同的样式

    第一列#id table tr td:first-child{ overflow: visible; }第二列table tr td:first-child+td{color:#666;}第三列tab ...

  8. 【黑客免杀攻防】读书笔记14 - 面向对象逆向-虚函数、MFC逆向

    虚函数存在是为了克服类型域解决方案的缺陷,以使程序员可以在基类里声明一些能够在各个派生类里重新定义的函数. 1 识别简单的虚函数 代码示例: #include "stdafx.h" ...

  9. MySQL分布式集群之MyCAT(二)【转】

    在第一部分,有简单的介绍MyCAT的搭建和配置文件的基本情况,这一篇详细介绍schema的一些具体参数,以及实际作用        首先贴上自己测试用的schema文件,双引号之前的反斜杠不会消除,姑 ...

  10. avalonJS-源码阅读(二)

    上一篇文章讲述的avalon刷页面所用到的几个函数.这篇则是主要讲avalon对刷DOM刷出来的avalon自定义属性如何处理的. 目录[-] avalon页面处理(2) 数据结构 解析avalon标 ...