【题目描述】

在暑假来临之际,小 Z 的地理老师布置了一个暑假作业,让同学们暑假期间 了解一下 C 国的铁路发展史。小 Z 在多番查证资料后发现,C 国在铁路发展初期, 铁路网络有着一个严密规整的结构:C 国的 N 个城市按层级分为首都、省会、省 辖市……由于在铁路发展初期,建造铁路花费巨大,为了避免不必要的浪费,铁 路网络的建设保证了任意两个城市相互连通,且仅有一条连通路径。 随后,小 Z 还查阅到历年来铁道部向全国上下发布的大小消息。由于多年来 C 国货币系统保持健康的 3%通胀率带来了稳定的物价上涨,铁道部发布的消息中 不乏对某段连接城市 u 与城市 v 铁路的价格上涨 w 元的通知。于是小 Z 不禁好奇, 在某些特定时间,在某个城市 p 的管辖区域内,任意两个城市间的铁路通勤的费 用和是多少。

【输入格式】

第一行输入两个正整数 N,Q,分别表示城市的数目和操作的数目。 接下来有 N–1 行,第 i 行是两个正整数 p[i], c[i],表示城市 p[i]是城市 i 的父亲结点,且连接 p[i]和 i 的铁路的初始收费为 c[i](1≤c[i]≤1000)。 再接下来有 Q 行,每行是如下两种类型之一: INC u v w (u, v, w 都是整数,且 1≤u, v≤N, 0≤w≤1000) ASK p (p 是整数,且 0≤p≤N) 意义如题目所述。

【输出格式】

对每个 ASK 类型的操作,输出所求的答案。请你输出答案对 2019 取模后的 结果。

【样例输入】

5 5

1 1

2 5

1 2

2 1

INC 2 4 2

INC 3 4 1

ASK 2

INC 2 5 3

ASK 1

【样例输出】

14 84

思路:

题目大意:给你一棵有根树,每条边有边权。实现两种操作:

1.给某一条路径上所 有边的权值加上一个数;

2.询问某棵子树内所有点对的距离和。 本题设置了几个部分分梯度,得部分分的做法有不少, 复杂度也各有千秋。下面给出比较容易理解的一种满分解 法。

从查询的角度思考,如何计算以 i 为根的子树内所有点 对的距离和?

不妨设点 x 与它的父亲 fa[x]相连的边的权值为 p[x],考虑 p[x]会对那些点对产生贡 献?显然是经过 x——fa[x]这条边的那些点对。

记 siz[x]为以 x 为根的子树的大小。则经过 x——fa[x]的点对有 siz[x]×(siz[i] – siz[x])对(如图 5),

于是,子树 i 内的点 x 的贡献就是 p[x]×siz[x]×siz[i] – p[x]×(siz[x])²。黄色的部分与 i 无关。

如果要计算,我们只需把子树 i 内所有点(不包括 i)的自己的黄色部分加起来,然后就可以求出答案。

这是因为 ∑(p[x]×siz[x]×siz[i] – p[x]×(siz[x])²) = siz[i]×∑(p[x]×siz[x]) – ∑(p[x]×(siz[x])²) 而修改操作,就是给一条路径上所有点(准确地说,不含 LCA)的 p 加上一个数。

我们要高效地维护上面黄色部分标出的两种“和”。这里有两种解法:

解法一

树链剖分 + DFS 序。 修改操作在树的链上进行,可以考虑使用树链剖分;而查询操作是查询子树的和,可 以考虑用 DFS 序。 树链剖分,把重链的结点在线段树中连续存放; 而 DFS 序,把子树结点连续存放。

两者可以兼得吗? 事实上,进行树链剖分的时候,我们 记 录了每个结点的“重儿子”,求树的 DFS 序 时, 我们对每个结点都先搜索它的重儿子再搜 索 其他儿子。

这样,就可以保证,DFS 序中, 每 条重链是连续存放的,每棵子树也是连续 存 放的,可以使用同一棵线段树存放。(不 妨 参考如图 6 的例子)

在线段树中,很容易 处 理让一段的值都加上一个数和查询一段的 和 这样的操作。 这样做是 O(n (log2n) 2)的。

代码:

  1. #include<bits/stdc++.h>
  2. typedef long long LL;
  3. const int N = 100000;
  4. const int M = 5000;
  5. const int inf = 2147483647;
  6. const int p = 2019;
  7. char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
  8. inline void _(char ch){*O++ = ch;}
  9. void print(int x) {if(x < 0) _('-'), x = -x; if(x>9) print(x/10);*O++ = x % 10 ^ 48;}
  10. inline int read(){
  11. int res = 0; char ch = getchar(); bool bo = false;
  12. while(ch < '0' || ch > '9') bo = (ch == '-'), ch = getchar();
  13. while(ch >= '0' && ch <= '9') res = (res << 1) + (res << 3) + (ch ^ 48), ch = getchar();
  14. return bo ? -res : res;
  15. }
  16. int getc() {
  17. char ch = getchar();
  18. while(ch != 'A' && ch != 'I') ch = getchar();
  19. return ch == 'I';
  20. }
  21. struct Edge {
  22. int to;
  23. Edge *nxt;
  24. Edge (int to, Edge *nxt) : to(to), nxt(nxt) {}
  25. }*head[N];
  26. int dep[N], a[N], size[N], siz[N], son[N], Top[N], fa[N], dfn[N], nfd[N], tot;
  27. struct Segment {
  28. struct node {
  29. int sum, tag, siz;
  30. int l, r;
  31. node *L, *R;
  32.  
  33. node(int l, int r) : sum(0), tag(0), siz(0), l(l), r(r), L(NULL), R(NULL) {}
  34.  
  35. void up() {
  36. siz = (L->siz + R->siz) % p;
  37. sum = (L->sum + R->sum) % p;
  38. }
  39.  
  40. void down() {
  41. L->sum = (L->sum + L->siz * tag) % p;
  42. R->sum = (R->sum + R->siz * tag) % p;
  43. L->tag = (L->tag + tag) % p; R->tag = (R->tag + tag) % p;
  44. tag = 0;
  45. }
  46.  
  47. int mid() {return (l + r) >> 1;}
  48.  
  49. }*root;
  50.  
  51. void bulid(node *&o, int l, int r, bool bo) {
  52. o = new node(l, r);
  53. if(l == r) {
  54. int Siz = siz[nfd[l]] % p;
  55. if(bo) Siz = ((LL)Siz * siz[nfd[l]]) % p;
  56. o->siz = Siz;
  57. o->sum = (Siz * a[nfd[l]]) % p;
  58. return;
  59. }
  60. bulid(o->L, l, o->mid(), bo);
  61. bulid(o->R, o->mid() + 1, r, bo);
  62. o->up();
  63. }
  64.  
  65. void chenge(node *o, int l, int r, int tag) {
  66. if(o->l >= l && o->r <= r) {
  67. o->sum = (o->sum + o->siz * tag) % p;
  68. o->tag = (o->tag + tag) % p;
  69. return;
  70. }
  71. if(o->tag) o->down();
  72. if(o->mid() >= l) chenge(o->L, l, r, tag);
  73. if(o->mid() < r) chenge(o->R, l, r, tag);
  74. o->up();
  75. }
  76.  
  77. int ask(node *o, int l, int r) {
  78. if(o->l >= l && o->r <= r) return o->sum;
  79. if(o->tag) o->down();
  80. int ans = 0;
  81. if(o->mid() >= l) ans += ask(o->L, l, r);
  82. if(o->mid() < r) ans += ask(o->R, l, r);
  83. return ans % p;
  84. }
  85.  
  86. }wfx, cdy;
  87.  
  88. void dfs(int x, int f) {
  89. dep[x] = dep[fa[x] = f] + (siz[x] = 1);
  90. for(Edge *i = head[x]; i; i = i->nxt) {
  91. if(i->to == f) continue;
  92. dfs(i->to, x);
  93. siz[x] += siz[i->to];
  94. if(siz[i->to] > siz[son[x]]) son[x] = i->to;
  95. }
  96. }
  97.  
  98. void dfs(int x, int f, int top) {
  99. Top[nfd[dfn[x] = ++tot] = x] = top;
  100. if(son[x]) dfs(son[x], x, top);
  101. for(Edge *i = head[x]; i; i = i->nxt) {
  102. if(i->to == son[x] || i->to == f) continue;
  103. dfs(i->to, x, i->to);
  104. }
  105. }
  106.  
  107. void chenge(int x, int y, int d) {
  108. if(x == y) return;
  109. while(Top[x] != Top[y]) {
  110. if(dep[Top[x]] < dep[Top[y]]) std::swap(x, y);
  111. wfx.chenge(wfx.root, dfn[Top[x]], dfn[x], d);
  112. cdy.chenge(cdy.root, dfn[Top[x]], dfn[x], d);
  113. x = fa[Top[x]];
  114. }
  115. if(x == y) return;
  116. if(dep[x] > dep[y]) std::swap(x, y);
  117. wfx.chenge(wfx.root, dfn[x] + 1, dfn[y], d), cdy.chenge(cdy.root, dfn[x] + 1, dfn[y], d);
  118. }
  119.  
  120. int ask(int k) {
  121. if(siz[k] <= 1) return 0;
  122. int a = wfx.ask(wfx.root, dfn[k] + 1, dfn[k] + siz[k] - 1), b = cdy.ask(cdy.root, dfn[k] + 1, dfn[k] + siz[k] - 1);
  123. return ((siz[k] * a - b) % p + p) % p;
  124. }
  125.  
  126. int main()
  127. {
  128. #ifdef yilnr
  129. #else
  130. freopen("network.in","r",stdin);
  131. freopen("network.out","w",stdout);
  132. #endif
  133. int n = read(), m = read();
  134. for(int i = 2; i <= n; ++i) {
  135. int x = read(); a[i] = read();
  136. head[x] = new Edge (i, head[x]);
  137. }
  138. dfs(1, 0);
  139. dfs(1, 0, 1);
  140. wfx.bulid(wfx.root, 1, n, false);
  141. cdy.bulid(cdy.root, 1, n, true);
  142. for(; m --> 0; ) {
  143. int opt = getc(), l, r, d;
  144. if(opt) l = read(), r = read(), d = read(), chenge(l, r, d);
  145. else printf("%d\n", ask(read()));
  146. }
  147. return 0;
  148. }

  

【csp模拟赛1】铁路网络 (network.cpp)的更多相关文章

  1. CSP模拟赛游记

    时间:2019.10.5 考试时间:100分钟(连正式考试时间的一半还没有到)题目:由于某些原因不能公开. 由于第一次接触NOIinux系统所以连怎么建文件夹,调字体,如何编译都不知道,考试的前半小时 ...

  2. 【csp模拟赛4】 珠江夜游 (cruise.cpp)-二分,贪心

    Problem 1 珠江夜游 (cruise.cpp) [题目描述] 小 Z 放假后难得来一趟广州游玩,当然要吃遍广州各路美食小吃然后再 到珠江新城看看远近闻名的小蛮腰啦!可当小 Z 一路吃吃吃以后, ...

  3. 【csp模拟赛4】基站建设 (station.cpp)

    [题目描述] 小 Z 的爸爸是一位通信工程师,他所在的通信公司最近接到了一个新的通 信工程建设任务,他们需要在 C 城建设一批新的基站. C 城的城市规划做得非常好,整个城市被规整地划分为 8 行 8 ...

  4. 【csp模拟赛5】限制 (restrict.cpp)--数学

    自己看吧: 爆搜代码: //春水初涨-春林初盛-春风十里-不如你 //----hzwer // 这是啥子题,读不懂-- //题意有问题 -- #include<iostream> #inc ...

  5. 【csp模拟赛5】购物(shopping.cpp)--常规

    多项式,因为每次的x相同,所以把a和b相加就行了,然后找对称轴,找离对称轴最近的整数点,然而我却写了个暴力,没看x #include <iostream> #include <cst ...

  6. 【csp模拟赛4】旅行计划 (travelling.cpp)--欧拉回路

    [题目描述] 小 Z 打算趁着暑假,开启他的旅行计划.但与其他同学不同的是,小 Z 旅 行时并不关心到达了哪个网红景点打了哪些卡.小 Z 更关注沿路的风光,而且 小 Z 觉得,尽管多次到达同一个地方, ...

  7. 【csp模拟赛1】不服来战 (challenge.cpp)

    [题目描述] 最近小 Z 和他的朋友都迷上了一款手机游戏:不服来战. 游戏的设定十分简单,在游戏开始时,会给出一排共 N 个灯,有的灯是开着 的有的是关着的,每个灯都有一个分数.而玩家可以进行任意次操 ...

  8. 【CSP模拟赛】Freda的迷宫(桥)

    题目描述 Freda是一个迷宫爱好者,她利用业余时间建造了许多迷宫.每个迷宫都是由若干房间和走廊构成的,每条走廊都连接着两个不同的房间,两个房间之间最多只有一条走廊直接相连,走廊都是双向通过.  黄昏 ...

  9. HGOI20191114 CSP模拟赛 反思

    Problem A 宇宙魔方 有一个$N \times N \times N$的魔方,每一次操作可以整体转动该魔方,也可以对于一层整体+X. 给出最后魔方的最终状态,其中有一个位置为-1.利用其它位置 ...

随机推荐

  1. Python学习3——列表和元组

    一.通用序列操作——索引.切片.相加.相乘.成员资格检查 1.索引,正序从0开始为第一个元素,逆序从-1开始,-1为最后一个元素 >>> greeting[0] 'h' >&g ...

  2. (转)如何真正实现由文档驱动的API设计?

    前言 本文主要介绍了一种新的开发思路:通过反转开发顺序,直接从API文档中阅读代码.作者认为通过这种开发方式,你可以更清楚地知道文档表达出什么以及它应该如何实现. 如果单从API文档出发,由于信息量不 ...

  3. 超详细,新手都能看懂 !使用SpringBoot+Dubbo 搭建一个简单的分布式服务

    来自:JavaGuide Github 地址:https://github.com/Snailclimb/springboot-integration-examples 目录: 使用 SpringBo ...

  4. scala的泛型浅析

    1. scala泛型浅析 package com.dtspark.scala.basics /** * 1,scala的类和方法.函数都可以是泛型. * * 2,关于对类型边界的限定分为上边界和下边界 ...

  5. Stanford NLP 课程笔记之计算字符串距离

    在自然语言处理任务中,有时候需要计算两个字符串之间的相似度,也可以称作是两者之间的距离,用最小编辑距离表示. 最小编辑距离用{Insertion,Deletion,Substitution}这三种操作 ...

  6. python+requests模拟登陆 学校选课系统

    最近学校让我们选课,每天都有不同的课需要选....然后突发奇想试试用python爬学校选课系统的课程信息 先把自己的浏览器缓存清空,然后在登陆界面按f12 如图: 可以看到登陆时候是需要验证码的,验证 ...

  7. angularJs同步请求

    今天在写几级联动的时候,因为比如上一个接口请求数据成功返回后,才能根据上一个接口返回的数据请求下一个接口,以此类推:因此有了同步请求的想法. 在前端做同步读取显然不是好的实践做法,同步之后会严重影响前 ...

  8. Marketing Cloud里取得系统contact数目的API

    Marketing Cloud里的Contact标准tile(下图红色tile)上是没有当前系统contact数字显示的,请对比profile tile(下图黑色tile). 客户有需求希望在Laun ...

  9. shell脚本——作业二(循环作业)

    1.通过位置变量创建linux系统账户及密码 $1 是执行脚本的第一个参数,$2 是执行脚本的第二个参数 #!/bin/bash #创建用户与密码 declare -i c=0 if [ -z $1 ...

  10. 三次样条插值 cubic spline interpolation

    什么是三次样条插值 插值(interpolation)是在已知部分数据节点(knots)的情况下,求解经过这些已知点的曲线, 然后根据得到的曲线进行未知位置点函数值预测的方法(未知点在上述已知点自变量 ...