标题效果:鉴于一棵树。每个节点有一个右值,所有节点正确启动值他们是0。有两种操作模式,0 x y代表x右所有点的子树的根值添加y。

1 k a1 b1 a2 b2 ……ak bk代表质疑。

共同拥有者k边缘( k <= 5),这些边保证是一个点到根节点的路径上的一段。

问这些路径段上的点的权值和是多少,可能有多条路径重叠的情况。

思路:子树改动,区间查询,非常明显用树链剖分解决,树链剖分维护一个size域。那么x的子树的范围就是pos[x]到pos[x] + size[x] - 1这一段上。能够用线段树区间改动。

关键是查询的时候。单查一条链肯定没什么问题。

可是假设几条链有交集的话就麻烦了。可是依据容斥原理我们知道,当我们把全部的路径都加过一次之后,两个路径重合的部分就计算重了。减掉。之后三个路径重合的部分减多了。再加上……我们仅仅要求出单个链的,两个路径重合的部分,三个路径重合的部分……这样就能够知道答案了。

怎样求多个链相交呢?我们先考虑两个链相交。因为每个路径保证是一个点到根节点的路径上的一段,那么两个链相交仅仅有一种情况。

例如以下图。

链1 2 3 4和2 3 5 6的交集就是2 3 。

观察一下。事实上3是4和6的LCA。2是两个链的顶端较深的那一个。不存在交集的情况就是链底的LCA深度深于当中的一条链的链顶。

多画几个图发现真的是这样。(事实上我仅仅是不会证明罢了。

。。

然后从1到1 << 5枚举取全部边的情况,计算取到n条边时的相交情况,n是计数就加上,是偶数就减去。

CODE:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. #define MAX 200010
  6. #define LEFT (pos << 1)
  7. #define RIGHT (pos << 1|1)
  8. #define CNT (r - l + 1)
  9. using namespace std;
  10.  
  11. pair<int,int> ask[MAX];
  12.  
  13. struct SegmentTree{
  14. int sum,c;
  15. }tree[MAX << 2];
  16.  
  17. int points,asks;
  18. int head[MAX],total;
  19. int next[MAX],aim[MAX];
  20.  
  21. int son[MAX],size[MAX],father[MAX],deep[MAX];
  22. int pos[MAX],top[MAX],cnt;
  23.  
  24. inline void Add(int x,int y)
  25. {
  26. next[++total] = head[x];
  27. aim[total] = y;
  28. head[x] = total;
  29. }
  30.  
  31. void PreDFS(int x,int last)
  32. {
  33. father[x] = last;
  34. deep[x] = deep[last] + 1;
  35. size[x] = 1;
  36. for(int i = head[x]; i; i = next[i]) {
  37. if(aim[i] == last) continue;
  38. PreDFS(aim[i],x);
  39. size[x] += size[aim[i]];
  40. if(size[aim[i]] > size[son[x]])
  41. son[x] = aim[i];
  42. }
  43. }
  44.  
  45. void DFS(int x,int _top)
  46. {
  47. pos[x] = ++cnt;
  48. top[x] = _top;
  49. if(son[x]) DFS(son[x],_top);
  50. for(int i = head[x]; i; i = next[i]) {
  51. if(aim[i] == father[x] || aim[i] == son[x]) continue;
  52. DFS(aim[i],aim[i]);
  53. }
  54. }
  55.  
  56. inline void PushDown(int pos,int cnt)
  57. {
  58. if(tree[pos].c) {
  59. tree[LEFT].c += tree[pos].c;
  60. tree[RIGHT].c += tree[pos].c;
  61. tree[LEFT].sum += tree[pos].c * (cnt - (cnt >> 1));
  62. tree[RIGHT].sum += tree[pos].c * (cnt >> 1);
  63. tree[pos].c = 0;
  64. }
  65. }
  66.  
  67. void Modify(int l,int r,int x,int y,int pos,int c)
  68. {
  69. if(l == x && r == y) {
  70. tree[pos].c += c;
  71. tree[pos].sum += CNT * c;
  72. return ;
  73. }
  74. PushDown(pos,CNT);
  75. int mid = (l + r) >> 1;
  76. if(y <= mid) Modify(l,mid,x,y,LEFT,c);
  77. else if(x > mid) Modify(mid + 1,r,x,y,RIGHT,c);
  78. else {
  79. Modify(l,mid,x,mid,LEFT,c);
  80. Modify(mid + 1,r,mid + 1,y,RIGHT,c);
  81. }
  82. tree[pos].sum = tree[LEFT].sum + tree[RIGHT].sum;
  83. }
  84.  
  85. int Ask(int l,int r,int x,int y,int pos)
  86. {
  87. if(l == x && r == y)
  88. return tree[pos].sum;
  89. PushDown(pos,CNT);
  90. int mid = (l + r) >> 1;
  91. if(y <= mid) return Ask(l,mid,x,y,LEFT);
  92. if(x > mid) return Ask(mid + 1,r,x,y,RIGHT);
  93. int left = Ask(l,mid,x,mid,LEFT);
  94. int right = Ask(mid + 1,r,mid + 1,y,RIGHT);
  95. return left + right;
  96. }
  97.  
  98. inline int Ask(int x,int y)
  99. {
  100. int re = 0;
  101. while(top[x] != top[y]) {
  102. if(deep[top[x]] < deep[top[y]])
  103. swap(x,y);
  104. re += Ask(1,cnt,pos[top[x]],pos[x],1);
  105. x = father[top[x]];
  106. }
  107. if(deep[x] < deep[y]) swap(x,y);
  108. re += Ask(1,cnt,pos[y],pos[x],1);
  109. return re;
  110. }
  111.  
  112. inline int GetLCA(int x,int y)
  113. {
  114. while(top[x] != top[y]) {
  115. if(deep[top[x]] < deep[top[y]])
  116. swap(x,y);
  117. x = father[top[x]];
  118. }
  119. return deep[x] < deep[y] ? x:y;
  120. }
  121.  
  122. inline bool Merge(pair<int,int> &a,pair<int,int> b)
  123. {
  124. if(deep[a.first] < deep[a.second]) swap(a.first,a.second);
  125. if(deep[b.first] < deep[b.second]) swap(b.first,b.second);
  126. int lca = GetLCA(a.first,b.first);
  127. if(deep[a.second] > deep[lca] || deep[b.second] > deep[lca]) return false;
  128. a.first = lca;
  129. a.second = deep[a.second] > deep[b.second] ? a.second:b.second;
  130. return true;
  131. }
  132.  
  133. inline int Calc(int cnt,int status)
  134. {
  135. int p = 0;
  136. for(int i = 0; i < cnt; ++i)
  137. p += (status >> i)&1;
  138. p = p&1 ? 1:-1;
  139. pair<int,int> now(0,0);
  140. for(int i = 0; i < cnt; ++i)
  141. if((status >> i)&1) {
  142. if(!now.first) now = ask[i + 1];
  143. else if(!Merge(now,ask[i + 1])) return 0;
  144. }
  145. //cout << status << ' ' << now.first << ' ' << now.second << ' ' << Ask(now.first,now.second) << ' ' << p << endl;
  146. return p * Ask(now.first,now.second);
  147. }
  148.  
  149. inline int MainTask(int cnt)
  150. {
  151. int re = 0;
  152. for(int i = 1; i <= cnt; ++i)
  153. scanf("%d%d",&ask[i].first,&ask[i].second);
  154. for(int i = 1; i < (1 << cnt); ++i)
  155. re += Calc(cnt,i);
  156. return re;
  157. }
  158.  
  159. int main()
  160. {
  161. cin >> points;
  162. for(int x,y,i = 1; i < points; ++i) {
  163. scanf("%d%d",&x,&y);
  164. Add(x,y);
  165. }
  166. PreDFS(1,0);
  167. DFS(1,1);
  168. cin >> asks;
  169. for(int flag,i = 1; i <= asks; ++i) {
  170. scanf("%d",&flag);
  171. if(!flag) {
  172. int x,y;
  173. scanf("%d%d",&x,&y);
  174. Modify(1,cnt,pos[x],pos[x] + size[x] - 1,1,y);
  175. }
  176. else {
  177. int cnt;
  178. scanf("%d",&cnt);
  179. printf("%d\n",MainTask(cnt)&0x7fffffff);
  180. }
  181. }
  182. return 0;
  183. }

版权声明:本文博客原创文章,博客,未经同意,不得转载。

BZOJ 3589 动态树 树链拆分+纳入和排除定理的更多相关文章

  1. BZOJ 3589 动态树(子树操作,链查询)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3589 题意:给出一棵有根树,两种操作:(1)以u为根的子树所有节点权值加上一个数字 ...

  2. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  3. BZOJ 3589: 动态树 树链剖分+线段树+树链的并

    利用树剖序的一些性质~ 这个题可以出到 $\sum k=10^5$ 左右. 做法很简单:每次暴力跳重链,并在线段树上查询链和. 查询之后打一个标记,把加过的链都置为 $0$.这样的话在同一次询问时即使 ...

  4. bzoj 3589: 动态树【树链剖分+容斥】

    因为一开始调试不知道unsigned怎么输出就没有加\n结果WA了一上午!!!!!然而最后放弃了unsigned选择了&2147483647 首先链剖,因为它所给的链一定是某个点到根的路径上的 ...

  5. 【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)

    3589: 动态树 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 405  Solved: 137[Submit][Status][Discuss] ...

  6. hdu5044 Tree 树链拆分,点细分,刚,非递归版本

    hdu5044 Tree 树链拆分.点细分.刚,非递归版本 //#pragma warning (disable: 4786) //#pragma comment (linker, "/ST ...

  7. 【BZOJ3589】动态树 树链剖分+线段树

    Description 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0: 这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1: 小明希望你 ...

  8. 【BZOJ】3319: 黑白树(并查集+特殊的技巧/-树链剖分+线段树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=3319 以为是模板题就复习了下hld............................. 然后n ...

  9. bzoj 3881 [Coci2015]Divljak fail树+树链的并

    题目大意 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: "1 P",Bob往自己的集合里添 ...

随机推荐

  1. 【android】在Eclipse在联想引jar包源代码

    (前提是你有jar包源代码!!) .确保Referenced LIbraies下已经有该jar包,否则的话,右击该jar包选build path->add to build path. 二.右键 ...

  2. 消息队列(Message Queue)基本概念(转)

    背景 之前做日志收集模块时,用到flume.另外也有的方案,集成kafaka来提升系统可扩展性,其中涉及到消息队列当时自己并不清楚为什么要使用消息队列.而在我自己提出的原始日志采集方案中不适用消息队列 ...

  3. jps查看java进程中哪个线程在消耗系统资源

    jps或ps -ef|grep java可以看到有哪些java进程,这个不用说了.但值得一提的是jps命令是依赖于/tmp下的某些文件 的. 而某些操作系统,定期会清理掉/tmp下的文件,导致jps无 ...

  4. 使用Hamcrest增强JUnit的测试能力

    package com.jadyer.service; import java.util.HashMap; import java.util.Map; import org.hamcrest.Matc ...

  5. Delphi F11 全屏

    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...

  6. django 带參数的 url

    url就像筋络一样把django这个大框架的各个部分紧紧的连接成一个总体,所以要了解django从url開始是一个不错的方向. 一般的view template url的关系这里就不讲了,以下会具体介 ...

  7. 经典排序算法 - 高速排序Quick sort

    经典排序算法 - 高速排序Quick sort 原理,通过一趟扫描将要排序的数据切割成独立的两部分,当中一部分的全部数据都比另外一部分的全部数据都要小,然后再按此方法对这两部分数据分别进行高速排序,整 ...

  8. Android该系统提供的服务--Vibrator(振子)

    Android该系统提供的服务--Vibrator(振子) --转载请注明出处:coder-pig Vibrator简单介绍与相关方法: watermark/2/text/aHR0cDovL2Jsb2 ...

  9. SQL Server提高并发查询效率

    同事写了个程序用创建多个线程使用ado同时对同个数据库进行相同的查询,涉及2张数据表的联查.当线程数非常多的情况下,读取数据的效率就会变得很慢,例如50个线程同时查询大概3000条数据,查询完成后通过 ...

  10. SQL Server 性能调优培训引言

    原文:SQL Server 性能调优培训引言 大家好,这是我在博客园写的第一篇博文,之所以要开这个博客,是我对MS SQL技术学习的一个兴趣记录. 作为计算机专业毕业的人,自己对技术的掌握总是觉得很肤 ...