题目背景

从前我是一位无名的旅人,旅途中我得到了某样东西:贤者之石。我因此得到悠久的时光和漂泊的生命。1897年冬天,我一时兴起舍弃了旅人的生活。

贤者之石创造出来的,是货真价实的黄金。我的名声传遍了整个国家。

题目描述

炼金术的要素,是炼金树和贤者之石。

炼金树是一棵含有n个节点的无根树,树上一共有n-1条石榴色的无向边。第i条无向边长度为Li。

我一共会使用m次炼金术。

每次使用炼金术时,我首先会把一块石榴色的贤者之石放在炼金树的某个节点x1上。然后,我会将若干块蓝色的贤者之石放在炼金树的其它K1个节点上。保证一个节点不会同时放入两块贤者之石。然后,我会使石榴色的贤者之石熔化。熔化后的贤者之石,只能沿着石榴色的边流动,既不会与蓝色的贤者之石接触,也不会进入蓝色的贤者之石所处的节点内。凝固后,含有石榴色的贤者之石的节点集合记为S1。很显然,S1是一个包含x1的连通块。记S1的大小为|S1|。

对于上图所示的炼金树,如果我把石榴色的贤者之石放在5号节点,把4块蓝色的贤者之石分别放在1、3、7、9号节点,那么熔化后石榴色的贤者之石就会流到2、5、6、8号节点。此时S1={2,5,6,8},|S1|=4。 然后,取出所有的贤者之石,选择x2、K2和新的K2个节点,用相同的方法,可以再次确定一个节点集合S2。记S2的大小为|S2|。你可以认为,确定S1的过程和确定S2的过程是互不干扰的。 最后,从S1中的每个节点分别向S2中的每个节点连一条长度为W的金色的有向边。注意,在同一次炼金术中连接的金色边长度都相同。

很显然,每次使用炼金术,都会增加|S1|*|S2|条有向边。 由于贤者之石熔化后只能沿石榴色的边流动,因此每次炼金术是相互独立的。

有时S1里面只会包含1个节点x,那么我可以不需要使用蓝色的贤者之石,直接将石榴色的贤者之石放在x号节点即可确定S1,此时令K1=-1。当然,我也可以用上述方法确定S2,此时令K2=-1。

使用完m次炼金术后,我会在1号节点灌入液态的黄金。黄金既可以沿石榴色的边流动,也可以沿金色的有向边流动。很显然,黄金流入i号节点的时间,就是1号节点到i号节点的最短路。

我想要知道,使用完m次炼金术后,黄金从1号节点流入每个节点的时间。

输入输出格式

输入格式:

第一行包括一个整数Test,表示测试点的编号。

第二行包括两个整数n,m。

接下来n-1行,第i行三个整数Ui,Vi,Li,表示一条从Ui到Vi长度为Li的无向边。

接下来5m行,表示m次炼金术。每次炼金术占五行:

第一行和第二行确定S1:

第一行一个整数X1,表示S1中石榴色的贤者之石的初始位置。

第二行第一个整数K1,

若K1=-1,表示S1 = {X1}。

若K1≥0,接下来K1个整数,表示K1块蓝色的贤者之石的位置。

第三行和第四行确定S2:

第三行一个整数X2,表示S2中石榴色的贤者之石的初始位置。

第四行第一个整数K2,

若K2=-1,表示S2 = {X2}。

若K2≥0,接下来K2个整数,表示K2块蓝色的贤者之石的位置。

第五行一个整数W,表示本次炼金术所连的所有金色边长度为W。

输入数据保证,

若K1≥0,则第二行K1个整数互不相同且不等于X1。

若K2≥0,则第四行K2个整数互不相同且不等于X2。

S1和S2可能有交集。保证0≤Li,W≤10^9。

输出格式:

共n行,每行一个整数,第i行表示1号点到i号点的最短路长度。

输入输出样例

输入样例#1:

  1. 0
  2. 6 2
  3. 1 2 10
  4. 2 3 10
  5. 2 4 10
  6. 1 5 10
  7. 5 6 1
  8. 1
  9. -1
  10. 3
  11. -1
  12. 5
  13. 2
  14. 3 3 4 5
  15. 5
  16. 2 3 6
  17. 3
输出样例#1:

  1. 0
  2. 3
  3. 5
  4. 3
  5. 3
  6. 4
  7.  
  8. 【样例1解释】
  9.  
  10. 初始情况下,1号点到每个点的最短路为0,10,20,20,10,11
  11. 第一次炼金术在原图中添加了一条从13,长度为5的有向边。
  12. 第一次炼金术后,1号点到每个点的最短路为0,10,5,20,10,11
  13. 第二次炼金术:
  14. X1=2,在3,4,5号节点放入蓝色的贤者之石,所以石榴色的贤者之石能流到1,2号节点。
  15. 注意石榴色的贤者之石不能流到6号节点,因为要流到6号节点必须经过5号节点。
  16. 所以S1 = {1,2}。
  17. X2=5,在3,6号节点放入蓝色的贤者之石,所以石榴色的贤者之石能流到1,2,5号节点。
  18. 所以S2 = {1,2,4,5}。
  19. S1中的每个节点分别向S2中的每个节点连长度为3的有向边,一共连了8条有向边。
  20. 第二次炼金术后,1号点到每个点的最短路为0,3,5,3,3,4

说明

n <= 10^5

m <= 20000

分析:这道题真的是太变态了,正解的难度和noip2016d1t2差不多.直接暴力spfa得分大概50分左右,最大的困难是要怎么连边,最短路大家都会,两两连边n高达10^5,数组都开不下,这个时候可以加过渡点,方法类似于:传送门,这样可以通过80%左右的数据,超时的原因还是因为边太多,观察条件可以发现连边的点构成的是一个区间,也就是说一组边向另外一组边连边,其实是一个区间向一个区间连边,树上区间,可以联想到dfs序+线段树来处理.

这个处理比较难,首先要开两个邻接表,一个是为了dfs的初始连边,一个是区间连边(实际上是dfs序),而且我们把区间简化为一个点,这个点不能和1~n中的任何一个点重复.

首先是建树,为了保证不会出现死循环,我们必须建两棵线段树,为什么?因为我们要有子区间到大区间的路径又要有大区间到子区间的路径,这些路径的边权都是0,如果不建两棵线段树就会死循环。这两棵线段树的连边顺序也必须区分清楚,第一个从小区间连向大区间,第二个从大区间连向小区间,考虑这样一个图:

中间的是过渡点,事实上我们的路径是:点--->区间--->点--->区间--->点,build操作负责第一四个操作,update负责第二三个操作,脑补一下就清楚了.线段树采用的是动态加点,因为我们根本不知道会有几个数.

现在考虑最难的dfs序问题,每个点的dfs序包含的不是它的子树吗?这样不就会包含多余的点吗?我们要怎么做才能让它只包含我们所需要的点呢?假设贤者之石放在点x,如果放置石头的点y不是x的祖先,那么我们要选出尽量多的子树不重叠的y出来,重叠的话合并一下成一棵子树.具体的方法是按照右端点排序,然后像单调栈那样处理.如果y是x的祖先怎么办?利用倍增将x向上跳,跳到y下面一个位置,记录最大的L,最小的R,为什么要这样呢?显然如果有很多祖先,肯定是取最近的祖先。因为每一个石头的子树都不能在区间里,所以我们前一个的右端点和后一个的左端点配对就可以了,具体是为什么我也不清楚QAQ,看看代码应该能理解.考场上还是打暴力吧......

300行代码:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cmath>
  6. #include <queue>
  7.  
  8. using namespace std;
  9.  
  10. const int maxn = ;
  11. const long long inf = 1LL << ;
  12.  
  13. int test, n, m, head1[maxn], to1[maxn], nextt1[maxn], w1[maxn], tot1 = ,x,k,L,R,tott,y,top,ww;
  14. long long ans[maxn], d[maxn];
  15. int head[maxn], to[maxn], nextt[maxn], w[maxn], tot = ,deep[maxn],fa[maxn][],c[maxn][],l[maxn],r[maxn],id[maxn],dfs_clock,cnt,root0,root1;
  16. bool vis[maxn];
  17.  
  18. struct node
  19. {
  20. int l, r;
  21. }a[maxn],b[maxn];
  22.  
  23. void add1(int x, int y, int z)
  24. {
  25. w1[tot1] = z;
  26. to1[tot1] = y;
  27. nextt1[tot1] = head1[x];
  28. head1[x] = tot1++;
  29. }
  30.  
  31. void add(int x, int y, int z)
  32. {
  33. w[tot] = z;
  34. to[tot] = y;
  35. nextt[tot] = head[x];
  36. head[x] = tot++;
  37. }
  38.  
  39. void dfs(int u, int from, int d)
  40. {
  41. l[u] = ++dfs_clock;
  42. id[dfs_clock] = u;
  43. deep[u] = d;
  44. for (int i = head1[u];i;i = nextt1[i])
  45. {
  46. int v = to1[i];
  47. if (v != from)
  48. {
  49. dfs(v, u, d + );
  50. fa[v][] = u;
  51. add(l[u], l[v], w1[i]);
  52. add(l[v], l[u], w1[i]);
  53. }
  54. }
  55. r[u] = dfs_clock;
  56. }
  57.  
  58. void build0(int l, int r, int &o)
  59. {
  60. if (l == r)
  61. {
  62. o = l;
  63. return;
  64. }
  65. o = ++cnt;
  66. int mid = (l + r) >> ;
  67. build0(l, mid, c[o][]);
  68. build0(mid + , r, c[o][]);
  69. add(c[o][], o, );
  70. add(c[o][], o, );
  71. }
  72.  
  73. void build1(int l, int r, int &o)
  74. {
  75. if (l == r)
  76. {
  77. o = l;
  78. return;
  79. }
  80. o = ++cnt;
  81. int mid = (l + r) >> ;
  82. build1(l, mid, c[o][]);
  83. build1(mid + , r, c[o][]);
  84. add(o, c[o][], );
  85. add(o, c[o][], );
  86. }
  87.  
  88. void update0(int l, int r, int o, int x, int y)
  89. {
  90. if (x <= l && r <= y)
  91. {
  92. add(o, cnt, );
  93. return;
  94. }
  95. int mid = (l + r) >> ;
  96. if (x <= mid)
  97. update0(l, mid, c[o][], x, y);
  98. if (y > mid)
  99. update0(mid + , r, c[o][], x, y);
  100. }
  101.  
  102. void update1(int l, int r, int o, int x, int y)
  103. {
  104. if (x <= l && r <= y)
  105. {
  106. add(cnt, o, ww);
  107. return;
  108. }
  109. int mid = (l + r) >> ;
  110. if (x <= mid)
  111. update1(l, mid, c[o][], x, y);
  112. if (y > mid)
  113. update1(mid + , r, c[o][], x, y);
  114. }
  115.  
  116. int climb(int x, int y)
  117. {
  118. for (int i = ; i >= ; i--)
  119. if (deep[fa[x][i]] > deep[y])
  120. x = fa[x][i];
  121. return x;
  122. }
  123.  
  124. bool cmp(node a, node b)
  125. {
  126. return a.r < b.r;
  127. }
  128.  
  129. void spfa()
  130. {
  131. queue <int> q;
  132. for (int i = ; i <= cnt; i++)
  133. d[i] = inf;
  134. d[] = ;
  135. vis[] = ;
  136. q.push();
  137. while (!q.empty())
  138. {
  139. int u = q.front();
  140. q.pop();
  141. vis[u] = ;
  142. for (int i = head[u]; i;i = nextt[i])
  143. {
  144. int v = to[i];
  145. if (d[v] > d[u] + w[i])
  146. {
  147. d[v] = d[u] + w[i];
  148. if (!vis[v])
  149. {
  150. vis[v] = ;
  151. q.push(v);
  152. }
  153. }
  154. }
  155. }
  156. }
  157.  
  158. int main()
  159. {
  160. scanf("%d%d%d", &test, &n, &m);
  161. for (int i = ; i < n; i++)
  162. {
  163. int u, v, l;
  164. scanf("%d%d%d", &u, &v, &l);
  165. add1(u, v, l);
  166. add1(v, u, l);
  167. }
  168. dfs(, , );
  169. for (int j = ; j <= ; j++)
  170. for (int i = ; i <= n; i++)
  171. fa[i][j] = fa[fa[i][j - ]][j - ];
  172. cnt = n;
  173. build0(, n, root0);
  174. build1(, n, root1);
  175. while (m--)
  176. {
  177. cnt++;
  178. L = ;
  179. R = n;
  180. scanf("%d%d", &x, &k);
  181. if (k < )
  182. update0(, n, root0, l[x], l[x]);
  183. else
  184. {
  185. tott = ;
  186. for (int i = ; i <= k; i++)
  187. {
  188. scanf("%d", &y);
  189. if (l[y] <= l[x] && r[x] <= r[y])
  190. {
  191. int t = climb(x, y);
  192. L = max(L, l[t]);
  193. R = min(R, r[t]);
  194. }
  195. else
  196. {
  197. b[++tott].l = l[y];
  198. b[tott].r = r[y];
  199. }
  200. }
  201. sort(b + , b + tott + , cmp);
  202. top = ;
  203. for (int i = ; i <= tott; i++)
  204. {
  205. while (top && a[top].l >= b[i].l)
  206. top--;
  207. if (!top || a[top].r + < b[i].l)
  208. a[++top] = b[i];
  209. else
  210. a[top].r = b[i].r;
  211. }
  212. a[].r = L - ;
  213. a[top + ].l = R + ;
  214. for (int i = ; i <= top; i++)
  215. if (a[i].r + < a[i + ].l)
  216. update0(, n, root0, a[i].r + , a[i + ].l - );
  217. }
  218.  
  219. scanf("%d%d", &x, &k);
  220. L = ;
  221. R = n;
  222. if (k < )
  223. {
  224. scanf("%d", &ww);
  225. update1(, n, root1, l[x], l[x]);
  226. }
  227. else
  228. {
  229. tott = ;
  230. for (int i = ; i <= k; i++)
  231. {
  232. scanf("%d", &y);
  233. if (l[y] <= l[x] && r[x] <= r[y])
  234. {
  235. int t = climb(x, y);
  236. L = max(L, l[t]);
  237. R = min(R, r[t]);
  238. }
  239. else
  240. {
  241. b[++tott].l = l[y];
  242. b[tott].r = r[y];
  243. }
  244. }
  245. sort(b + , b + tott + , cmp);
  246. top = ;
  247. for (int i = ; i <= tott; i++)
  248. {
  249. while (top && a[top].l >= b[i].l)
  250. top--;
  251. if (!top || a[top].r + < b[i].l)
  252. a[++top] = b[i];
  253. else
  254. a[top].r = b[i].r;
  255. }
  256. a[].r = L - ;
  257. a[top + ].l = R + ;
  258. scanf("%d", &ww);
  259. for (int i = ; i <= top; i++)
  260. if (a[i].r + < a[i + ].l)
  261. update1(, n, root1, a[i].r + , a[i + ].l - );
  262. }
  263. }
  264. spfa();
  265. for (int i = ; i <= n; i++)
  266. ans[id[i]] = d[i];
  267. for (int i = ; i <= n; i++)
  268. printf("%lld\n", ans[i]);
  269.  
  270. return ;
  271. }

常州模拟赛d3t3 两只怪物心心相印的更多相关文章

  1. 常州模拟赛d7t3 水管

    分析:第一问还是很好做的,关键是怎么做第二问.我们可以每次删掉最小生成树上的一条边,然后再求一次最小生成树,看边权和大小和原来的是不是一样的,不过这个做法效率很低. 考虑Kruskal算法的原理,每次 ...

  2. 常州模拟赛d4t1 立方体

    题目描述 立方体有 6 个面,每个面上有一只奶牛,每只奶牛都有一些干草.为了训练奶牛的合作精神,它 们在玩一个游戏,每轮:所有奶牛将自己的干草分成 4 等份,分给相邻的 4 个面上的奶牛. 游戏开始, ...

  3. 常州模拟赛d2t3 小X的佛光

    平日里最喜欢做的事就是蒸发学水.[题目描述]小 X 所在的城市 X 城是一个含有 N 个节点的无向图,同时,由于 X 国是一个发展中国家,为了节约城市建设的经费,X 国首相在建造 X 城时只建造 N ...

  4. 常州模拟赛d2t1 小X的质数

    题目背景 小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的 情感.小 X 认为,质数是一切自然数起源的地方. 题目描述 在小 X 的认知里,质数是除了本身和 1 以外,没有其他因 ...

  5. 常州模拟赛d8t1 友好数对

    分析:其实就是问你有多少对a,b有且仅有两位不相同.我们可以先枚举这两位,对应ai枚举一位,对应bi枚举一位,如果ai^(1<<x) == bi^(1<<y),证明恰好有两位不 ...

  6. 常州模拟赛d7t2 数组

    题目背景 HJZ 有很多玩具.他最喜欢玩的玩具是一个可以变化的数组. 题目描述 HJZ 的数组初始时有 n 个元素.他可以把一个位置上的数加上或减去一个固定的 数 x. 一天 LJZ 和 HZY 来 ...

  7. [NOIP2018模拟赛10.19]只会暴力报告

    闲扯 今天又是暴力满满(并不)的一天呢 昨天老师说了分数要正态分布,今天看起来...不过暴力分很多,虽然我人太傻逼又没打满 T1 woc?不是说送分的吗,看起来又是个树形DP神题,暴力告辞,链上的搞一 ...

  8. 常州模拟赛d6t3 噪音

    FJ有M个牛棚,编号1至M,刚开始所有牛棚都是空的.FJ有N头牛,编号1至N,这N头牛按照编号从小到大依次排队走进牛棚,每一天只有一头奶牛走进牛棚.第i头奶牛选择走进第p[i]个牛棚.由于奶牛是群体动 ...

  9. bzoj3743 [Coci2015]Kamp 常州模拟赛d6t2

    3743: [Coci2015]Kamp Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 484  Solved: 229[Submit][Status ...

随机推荐

  1. 洛谷 P1311 选择客栈

    题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均 ...

  2. 在ABAP里模拟实现Java Spring的依赖注入

    Dependency Injection- 依赖注入,在Java Spring框架中有着广泛地应用.通过依赖注入,我们不必在应用代码里繁琐地初始化依赖的资源,非常方便. 那么ABAP能否从语言层面上也 ...

  3. (转)SpringMVC学习(二)——SpringMVC架构及组件

    http://blog.csdn.net/yerenyuan_pku/article/details/72231385 相信大家通过前文的学习,已经对SpringMVC这个框架多少有些理解了.还记得上 ...

  4. JS常用操作节点的方法

    js常见的创建dom节点的方法有 createElement() 创建一个元素节点 => 接收参数为string类型的nodename createTextNode() 创建一个文本节点 =&g ...

  5. 行内元素的padding和margin是否无效

    html中元素分为三种:块级元素.行内元素(也叫内联元素),内联块级元素. 常用块级元素:<div>.<p>.<h1>...<h6>.<ol> ...

  6. Springboot 命令注入属性[--]&[-D]

    场景 在用Jenkins,做自动化部署时,遇到一些命令问题. 需要通过命令的形式,注入些业务值. -D 系统属性注入 Java,启动jar 命令: java [ options ] -jar file ...

  7. 实体类和JSON对象之间相互转化

    . [代码]工具类 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 3 ...

  8. cookies,sessionStorage和localStorage的相同点和不同点?

    相同点:都存储在客户端. 不同点: 1.存储大小: cookies数据大小不能超过4k sessionStorage和localStorage虽然也有存储大小的限制,但比cookies大得多,可以达到 ...

  9. 【线段树】uoj#228. 基础数据结构练习题

    get到了标记永久化 sylvia 是一个热爱学习的女孩子,今天她想要学习数据结构技巧. 在看了一些博客学了一些姿势后,她想要找一些数据结构题来练练手.于是她的好朋友九条可怜酱给她出了一道题. 给出一 ...

  10. 初涉KMP算法

    久仰字符串系列理论 KMP 讲解(引用自bzoj3670动物园) 某天,园长给动物们讲解KMP算法. 园长:“对于一个字符串S,它的长度为L.我们可以在O(L)的时间内,求出一个名为next的数组.有 ...