题目描述

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

输入输出格式

输入格式:

第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

输出格式:

输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模

输入输出样例

输入样例#1:
复制

  1. 5 5 2 24
  2. 7 3 7 8 0
  3. 1 2
  4. 1 5
  5. 3 1
  6. 4 1
  7. 3 4 2
  8. 3 2 2
  9. 4 5
  10. 1 5 1 3
  11. 2 1 3
输出样例#1: 复制

  1. 2
  2. 21

说明

时空限制:1s,128M

数据规模:

对于30%的数据: N≤10,M≤10

对于70%的数据: N≤10^3,M≤10^3

对于100%的数据: N≤10^5,M≤10^5

其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233

样例说明:

树的结构如下:

各个操作如下:

故输出应依次为2、21(重要的事情说三遍:记得取模)

题解

我也是会树剖的女人了!!!嗷嗷嗷嗷嗷嗷嗷嗷嗷嗷

模板题嘛QAQ,也没什么好讲的

剖了之后,对于操作1和2,在求lca的过程中做

对于操作3和4,直接在dfn[x]和dfn[x]+siz[x]-1上搞事就星了

其实操作1和2可以用树上前缀和水水水水水水(不对要随时询问好像布星QAQ)

  1. #include<cstdio>
  2. #include<iostream>
  3. using namespace std;
  4. const int MAXN=2e5+;
  5. int val[MAXN];//点权
  6. //以下建原树
  7. struct emm{
  8. int e,f;
  9. }b[*MAXN];
  10. int h[MAXN];
  11. int tot=;
  12. void con(int x,int y)
  13. {
  14. b[++tot].f=h[x];
  15. h[x]=tot;
  16. b[tot].e=y;
  17. b[++tot].f=h[y];
  18. h[y]=tot;
  19. b[tot].e=x;
  20. return;
  21. }
  22. //第一遍dfs
  23. int d[MAXN],fa[MAXN],top[MAXN],z[MAXN],siz[MAXN];
  24. void dfs(int x)
  25. {
  26. siz[x]=;
  27. top[x]=x;
  28. int mac=,macc=-;
  29. for(int i=h[x];i;i=b[i].f)
  30. if(!d[b[i].e])
  31. {
  32. d[b[i].e]=d[x]+;
  33. fa[b[i].e]=x;
  34. dfs(b[i].e);
  35. siz[x]+=siz[b[i].e];
  36. if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];}
  37. }
  38. z[x]=mac;
  39. top[mac]=x;
  40. return;
  41. }
  42. //第二遍dfs
  43. int q[MAXN],dfn[MAXN];
  44. void dfss(int x)
  45. {
  46. q[++tot]=x;
  47. dfn[x]=tot;
  48. if(z[x])dfss(z[x]);
  49. for(int i=h[x];i;i=b[i].f)
  50. if(fa[b[i].e]==x&&b[i].e!=z[x])
  51. dfss(b[i].e);
  52. return;
  53. }
  54. //找top
  55. int fitop(int x)
  56. {
  57. if(top[x]==x)return x;
  58. return top[x]=fitop(top[x]);
  59. }
  60. //建树完成
  61. int n,m,s;
  62. long long mod;
  63. //以下线段树
  64. struct ahh{
  65. int l,r;
  66. long long v,laz;
  67. }a[*MAXN];
  68. void build(int i,int ll,int rr)
  69. {
  70. a[i].l=ll;
  71. a[i].r=rr;
  72. if(ll==rr){a[i].v=val[q[ll]];return;}
  73. int mid=(ll+rr)>>;
  74. build((i<<),ll,mid);
  75. build(((i<<)|),mid+,rr);
  76. a[i].v=a[(i<<)].v+a[((i<<)|)].v%mod;
  77. return;
  78. }
  79. void add(int i,int ll,int rr,int k)
  80. {
  81. if(a[i].l==ll&&a[i].r==rr)
  82. {a[i].laz+=k;return;}
  83. a[i].v=(long long)a[i].v+(rr-ll+)*k%mod;
  84. int mid=(a[i].l+a[i].r)>>;
  85. if(rr<=mid)add((i<<),ll,rr,k);
  86. else if(mid+<=ll)add(((i<<)|),ll,rr,k);
  87. else {add((i<<),ll,mid,k);add(((i<<)|),mid+,rr,k);}
  88. return;
  89. }
  90. void pushtag(int i)
  91. {
  92. if(!a[i].laz)return;
  93. a[i].v=(long long)a[i].v+a[i].laz*(a[i].r-a[i].l+)%mod;
  94. if(a[i].l==a[i].r){a[i].laz=;return;}
  95. a[(i<<)].laz+=a[i].laz;
  96. a[((i<<)|)].laz+=a[i].laz;
  97. a[i].laz=;
  98. return;
  99. }
  100. unsigned long long ans;
  101. void find(int i,int ll,int rr)
  102. {
  103. pushtag(i);
  104. if(a[i].l==ll&&a[i].r==rr){ans=(ans+a[i].v)%mod;return;}
  105. int mid=(a[i].l+a[i].r)>>;
  106. if(rr<=mid)find((i<<),ll,rr);
  107. else if(ll>=mid+)find(((i<<)|),ll,rr);
  108. else {find((i<<),ll,mid);find(((i<<)|),mid+,rr);}
  109. return;
  110. }
  111. //
  112. int main()
  113. {
  114. //freopen("a.in","r",stdin);
  115. scanf("%d%d%d%lld",&n,&m,&s,&mod);
  116. for(int i=;i<=n;++i)
  117. scanf("%d",&val[i]);
  118. for(int i=;i<n;++i)
  119. {
  120. int x,y;
  121. scanf("%d%d",&x,&y);
  122. con(x,y);
  123. }
  124. d[s]=;
  125. dfs(s);
  126. tot=;
  127. dfss(s);
  128. for(int i=;i<=n;++i)
  129. top[i]=fitop(i);
  130. build(,,n);
  131. //run
  132. for(int c=;c<=m;++c)
  133. {
  134. int opt;
  135. scanf("%d",&opt);
  136. if(opt==)
  137. {
  138. int x,y,z;
  139. scanf("%d%d%d",&x,&y,&z);
  140. //lca
  141. while(top[x]!=top[y])
  142. {
  143. if(d[top[x]]>d[top[y]])
  144. {
  145. add(,dfn[top[x]],dfn[x],z);
  146. x=fa[top[x]];
  147. }
  148. else
  149. {
  150. add(,dfn[top[y]],dfn[y],z);
  151. y=fa[top[y]];
  152. }
  153. }
  154. if(d[x]>d[y])add(,dfn[y],dfn[x],z);
  155. else add(,dfn[x],dfn[y],z);
  156. }
  157. else if(opt==)
  158. {
  159. int x,y;
  160. scanf("%d%d",&x,&y);
  161. ans=;
  162. while(top[x]!=top[y])
  163. {
  164. if(d[top[x]]>d[top[y]])
  165. {
  166. find(,dfn[top[x]],dfn[x]);
  167. ans%=mod;
  168. x=fa[top[x]];
  169. }
  170. else
  171. {
  172. find(,dfn[top[y]],dfn[y]);
  173. ans%=mod;
  174. y=fa[top[y]];
  175. }
  176. }
  177. if(d[x]>d[y])find(,dfn[y],dfn[x]);
  178. else find(,dfn[x],dfn[y]);
  179. printf("%lld\n",ans%mod);
  180. }
  181. else if(opt==)
  182. {
  183. int x,z;
  184. scanf("%d%d",&x,&z);
  185. add(,dfn[x],dfn[x]+siz[x]-,z);
  186. }
  187. else
  188. {
  189. int x;
  190. scanf("%d",&x);
  191. ans=;
  192. find(,dfn[x],dfn[x]+siz[x]-);
  193. printf("%lld\n",ans%mod);
  194. }
  195. }
  196. return ;
  197. }

「LuoguP3384」【模板】树链剖分的更多相关文章

  1. 「POJ3237」Tree(树链剖分)

    题意 给棵n个点的树.边有边权然后有三种操作 1.CHANGE i v 将编号为i的边权变为v 2.NEGATE a b 将a到b的所有边权变为相反数. 3.QUERY a b 查询a b路径的最大边 ...

  2. 「HNOI2015」开店(树链剖分, 主席树)

    /* 考虑将所求的值拆分 记每个点到根的路径长度为dis_i, 那么我们要求的就是\sum_{i = l} ^ r dis_i + dis[u] * (r - l + 1) - 2\sum_{i = ...

  3. luoguP3384 [模板]树链剖分

    luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #inc ...

  4. [luogu P3384] [模板]树链剖分

    [luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...

  5. [洛谷P3384] [模板] 树链剖分

    题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...

  6. loj#6073. 「2017 山东一轮集训 Day5」距离(树链剖分 主席树)

    题意 题目链接 Sol 首先对询问差分一下,我们就只需要统计\(u, v, lca(u, v), fa[lca(u, v)]\)到根的路径的贡献. 再把每个点与\(k\)的lca的距离差分一下,则只需 ...

  7. 模板 树链剖分BFS版本

    //点和线段树都从1开始 //边使用vector vector<int> G[maxn]; ],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn], ...

  8. P3384 [模板] 树链剖分

    #include <bits/stdc++.h> using namespace std; typedef long long ll; int n, m, rt, mod, cnt, to ...

  9. 树链剖分详解(洛谷模板 P3384)

    洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 emm还有必备的 链式前向星.线段树 也要先学了. 如果这三个知识点没掌握好的话,树链剖 ...

  10. 『题解』洛谷P3384 【模板】树链剖分

    Problem Portal Portal1: Luogu Description 如题,已知一棵包含\(N\)个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作\(1\): ...

随机推荐

  1. AC日记——草地排水 codevs 1993

    1993 草地排水 USACO  时间限制: 2 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 在农夫约翰的农场上,每 ...

  2. (46)C#注册表及读写

    启动注册表:regedit 结构: 注册表一共有7个配置单元用regedit只能看到5个 HKEY_CLASSES_ROOT 包含系统上文件类型的细节(.txt,.doc)等.以及使用那些应用程序可以 ...

  3. T1164 统计数字 codevs

    http://codevs.cn/problem/1164/ 题目描述 Description [问题描述]某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*109).已知不 ...

  4. ssh的安装和使用

    1.ssh的安装 服务器端:sudo apt-get install openssh-serve 客户端:sudo apt-get install openssh-client 2.ssh的操作 查看 ...

  5. CS Academy #32 G

    题意: 分析: 考虑如何求方案数 dp[i][j]表示i个数字的和为j的方案数,这是个经典问题,转移有两种,一个是填一个数字1,一个是整体加1 然后这个问题并不是求方案数,而是求对应的权值和 我们很容 ...

  6. 基于Android的远程视频监控系统(含源码)

    基本过程是android作为socket客户端将采集到的每一帧图像数据发送出去,PC作为服务器接收并显示每一帧图像实现远程监控.图片如下(后来PC端加了个拍照功能)... (PS.刚学android和 ...

  7. [转]java中的字符串相关知识整理

    字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...

  8. Mysql学习之十二:JDBC连接数据库之DriverManager方法

    JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包括7个步骤: 1.载入JDBC驱动程序: 在连接数据库之前.首先要载入想要连接的数据库的驱动到JVM(Java虚拟机). 这通过java.l ...

  9. js 日期 (10 + '').length == 10 ? '0' + 10 : 10;

    js 日期 (10 + '').length == 10 ? '0' + 10 : 10;

  10. Appium基于安卓的各种FindElement的控件定位

    转自:http://www.2cto.com/kf/201410/340345.html 1. findElementByName 1.1 示例 ? 1 2 el = driver.findEleme ...