4127: Abs

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 11  Solved: 5
[Submit][Status][Discuss]

Description

  1. 给定一棵树,设计数据结构支持以下操作
  2.  
  3. 1 u v d  表示将路径 (u,v) d
  4.  
  5. 2 u v 表示询问路径 (u,v) 上点权绝对值的和

Input

第一行两个整数n和m,表示结点个数和操作数
  1. 接下来一行n个整数a_i,表示点i的权值
  2.  
  3. 接下来n-1行,每行两个整数u,v表示存在一条(u,v)的边
  4.  
  5. 接下来m行,每行一个操作,输入格式见题目描述

Output

对于每个询问输出答案

Sample Input

4 4
-4 1 5 -2
1 2
2 3
3 4
2 1 3
1 1 4 3
2 1 3
2 3 4

Sample Output

10
13
9

HINT

对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8

  我们分开处理正数负数情况,注意加数为正,所以一个负数被加成正数最多发生O(n)次,我们需要实现的就是快速的判定是否有某个负数加成了正数,维护负数集合中的最大值和位置即可。如果负数集合的最大值大于0,那么我们求得最大值所在位置,然后暴力将它修改到正数集合即可。

  注意这道题INF取0x3f3f3f3f要出事。

  第一次写链剖的每个链单独建线段树版本,不是太难。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. #define MAXN 210000
  7. #define MAXT MAXN*4
  8. #define MAXV MAXN
  9. #define MAXE MAXN*2
  10. #define INFL 0x3f3f3f3f3f3f3f3f
  11. #define smid ((l+r)>>1)
  12. #define abs(x) ((x)>0?x:-(x))
  13. typedef long long qword;
  14. inline int nextInt()
  15. {
  16. register char ch;
  17. register int x=;
  18. register bool f=false;
  19. while (ch=getchar(),ch<'' || ch>'')f|=ch=='-';
  20. while (x=x*+ch-'',ch=getchar(),ch<='' && ch>='');
  21. return x*(f?-:);
  22. }
  23. struct sgt_node
  24. {
  25. int lc,rc;
  26. int sd;
  27. qword sv;
  28. qword pls;
  29. pair<qword,int> mx;
  30. }sgt[MAXT];
  31. int topt=;
  32. int a[MAXN];
  33. int b[MAXN];
  34. void update(int now)
  35. {
  36. sgt[now].mx=max(sgt[sgt[now].lc].mx,sgt[sgt[now].rc].mx);
  37. sgt[now].sd=sgt[sgt[now].lc].sd+sgt[sgt[now].rc].sd;
  38. sgt[now].sv=sgt[sgt[now].lc].sv+sgt[sgt[now].rc].sv;
  39. }
  40. void make_plus(int now,int l,int r,qword delta)
  41. {
  42. sgt[now].sv+=(qword)sgt[now].sd*delta;
  43. sgt[now].pls+=delta;
  44. sgt[now].mx.first+=delta;
  45. }
  46. void down(int now,int l,int r)
  47. {
  48. if (sgt[now].pls)
  49. {
  50. make_plus(sgt[now].lc,l,smid,sgt[now].pls);
  51. make_plus(sgt[now].rc,smid+,r,sgt[now].pls);
  52. sgt[now].pls=;
  53. }
  54. }
  55. void Build_sgt(int &now,int l,int r)
  56. {
  57. now=++topt;
  58. if (l==r)
  59. {
  60. sgt[now].sd=b[l]<?-:;
  61. sgt[now].sv=abs(b[l]);
  62. if (b[l]<)
  63. {
  64. sgt[now].mx=make_pair(b[l],l);
  65. }else
  66. {
  67. sgt[now].mx=make_pair(-INFL,-);
  68. }
  69. return ;
  70. }
  71. Build_sgt(sgt[now].lc,l,smid);
  72. Build_sgt(sgt[now].rc,smid+,r);
  73. update(now);
  74. }
  75. void Add_sgt(int now,int l,int r,int x,int y,int delta)
  76. {
  77. if (l==x && r==y)
  78. {
  79. make_plus(now,l,r,delta);
  80. return ;
  81. }
  82. down(now,l,r);
  83. if (y<=smid)
  84. Add_sgt(sgt[now].lc,l,smid,x,y,delta);
  85. else if (smid<x)
  86. Add_sgt(sgt[now].rc,smid+,r,x,y,delta);
  87. else
  88. {
  89. Add_sgt(sgt[now].lc,l,smid,x,smid,delta);
  90. Add_sgt(sgt[now].rc,smid+,r,smid+,y,delta);
  91. }
  92. update(now);
  93. }
  94. void Modify_sgt(int now,int l,int r,int pos,qword v)
  95. {
  96. if (l==r)
  97. {
  98. if (v<)
  99. sgt[now].mx=make_pair(v,l);
  100. else
  101. sgt[now].mx=make_pair(-INFL,-);
  102. sgt[now].sd=v<?-:;
  103. sgt[now].sv=abs(v);
  104. sgt[now].pls=;
  105. return ;
  106. }
  107. down(now,l,r);
  108. if (pos<=smid)
  109. Modify_sgt(sgt[now].lc,l,smid,pos,v);
  110. else
  111. Modify_sgt(sgt[now].rc,smid+,r,pos,v);
  112. update(now);
  113. }
  114. pair<qword,int> Query_sgt_max(int now,int l,int r,int x,int y)
  115. {
  116. if (l==x && r==y)
  117. {
  118. return sgt[now].mx;
  119. }
  120. down(now,l,r);
  121. if (y<=smid)
  122. return Query_sgt_max(sgt[now].lc,l,smid,x,y);
  123. else if (smid<x)
  124. return Query_sgt_max(sgt[now].rc,smid+,r,x,y);
  125. else
  126. return max(Query_sgt_max(sgt[now].lc,l,smid,x,smid),
  127. Query_sgt_max(sgt[now].rc,smid+,r,smid+,y));
  128. }
  129. qword Query_sgt_sum(int now,int l,int r,int x,int y)
  130. {
  131. if (l==x && r==y)
  132. return sgt[now].sv;
  133. down(now,l,r);
  134. if (y<=smid)
  135. return Query_sgt_sum(sgt[now].lc,l,smid,x,y);
  136. else if (smid<x)
  137. return Query_sgt_sum(sgt[now].rc,smid+,r,x,y);
  138. else
  139. return Query_sgt_sum(sgt[now].lc,l,smid,x,smid)+
  140. Query_sgt_sum(sgt[now].rc,smid+,r,smid+,y);
  141. }
  142. struct Edge
  143. {
  144. int np;
  145. Edge *next;
  146. }E[MAXE],*V[MAXV];
  147. int tope=-;
  148. void addedge(int x,int y)
  149. {
  150. E[++tope].np=y;
  151. E[tope].next=V[x];
  152. V[x]=&E[tope];
  153. }
  154. int q[MAXN];
  155. int depth[MAXN],top[MAXN],son[MAXN];
  156. int pnt[MAXN],siz[MAXN];
  157. int pos[MAXN],dfstime;
  158. int spos[MAXN],tpos[MAXN];
  159. void bfs(int now)
  160. {
  161. int head=-,tail=;
  162. Edge *ne;
  163. q[]=now;
  164. depth[now]=;
  165. while (head<tail)
  166. {
  167. now=q[++head];
  168. for (ne=V[now];ne;ne=ne->next)
  169. {
  170. if (ne->np==pnt[now])continue;
  171. pnt[ne->np]=now;
  172. depth[ne->np]=depth[now]+;
  173. q[++tail]=ne->np;
  174. }
  175. }
  176. for (int i=tail;i>=;i--)
  177. {
  178. now=q[i];
  179. siz[now]=;
  180. int mxsiz=;
  181. for (ne=V[now];ne;ne=ne->next)
  182. {
  183. if (ne->np==pnt[now])continue;
  184. siz[now]+=siz[ne->np];
  185. if (siz[ne->np]>mxsiz)
  186. {
  187. mxsiz=siz[ne->np];
  188. son[now]=ne->np;
  189. }
  190. }
  191. }
  192. }
  193. int stack[MAXN],tops=-;
  194. void dfs(int now)
  195. {
  196. Edge *ne;
  197. memset(spos,0x3f,sizeof(spos));
  198. memset(tpos,,sizeof(tpos));
  199. stack[++tops]=now;
  200. top[now]=now;
  201. while (~tops)
  202. {
  203. now=stack[tops--];
  204. pos[now]=++dfstime;
  205. tpos[top[now]]=max(tpos[top[now]],pos[now]);
  206. spos[top[now]]=min(spos[top[now]],pos[now]);
  207. for (ne=V[now];ne;ne=ne->next)
  208. {
  209. if (ne->np==pnt[now] || ne->np==son[now])continue;
  210. stack[++tops]=ne->np;
  211. top[ne->np]=ne->np;
  212. }
  213. if (son[now])
  214. {
  215. stack[++tops]=son[now];
  216. top[son[now]]=top[now];
  217. }
  218. }
  219. }
  220. int troot[MAXN];
  221.  
  222. int main()
  223. {
  224. freopen("input.txt","r",stdin);
  225. int n,m,x,y,z;
  226. scanf("%d%d",&n,&m);
  227. for (int i=;i<=n;i++)
  228. a[i]=nextInt();
  229. for (int i=;i<n;i++)
  230. {
  231. x=nextInt();y=nextInt();
  232. //scanf("%d%d",&x,&y);
  233. addedge(x,y);
  234. addedge(y,x);
  235. }
  236. bfs();
  237. dfs();
  238. for (int i=;i<=n;i++)
  239. b[pos[i]]=a[i];
  240. for (int i=;i<=n;i++)
  241. {
  242. if (top[i]==i)
  243. Build_sgt(troot[i],spos[i],tpos[i]);
  244. else
  245. troot[i]=-;
  246. }
  247. int opt;
  248. for (int i=;i<m;i++)
  249. {
  250. opt=nextInt();
  251. //scanf("%d",&opt);
  252. if (opt==)
  253. {
  254. x=nextInt();y=nextInt();z=nextInt();
  255. //scanf("%d%d%d",&x,&y,&z);
  256. while (true)
  257. {
  258. if (top[x]==top[y])
  259. {
  260. if (pos[x]>pos[y])swap(x,y);
  261. Add_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y],z);
  262. while (true)
  263. {
  264. pair<qword,int> pr;
  265. pr=Query_sgt_max(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y]);
  266. if (pr.first<=)break;
  267. Modify_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pr.second,pr.first);
  268. }
  269. break;
  270. }
  271. if (depth[top[x]]<depth[top[y]])swap(x,y);
  272. Add_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x],z);
  273. while (true)
  274. {
  275. pair<qword,int> pr;
  276. pr=Query_sgt_max(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x]);
  277. if (pr.first<=)break;
  278. Modify_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pr.second,pr.first);
  279. }
  280. x=pnt[top[x]];
  281. }
  282. }else
  283. {
  284. //scanf("%d%d",&x,&y);
  285. x=nextInt();y=nextInt();
  286. qword res=;
  287. while (true)
  288. {
  289. if (top[x]==top[y])
  290. {
  291. if (pos[x]>pos[y])swap(x,y);
  292. res+=Query_sgt_sum(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y]);
  293. break;
  294. }
  295. if (depth[top[x]]<depth[top[y]])swap(x,y);
  296. res+=Query_sgt_sum(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x]);
  297. x=pnt[top[x]];
  298. }
  299. printf("%lld\n",res);
  300. }
  301. }
  302. }

bzoj 4127: Abs 树链剖分的更多相关文章

  1. BZOJ 4127: Abs (树链剖分 线段树求区间绝对值之和 带区间加法)

    题意 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d(d>=0) 2 u v 表示询问路径 (u,v) 上点权绝对值的和 分析 绝对值之和不好处理,那么我们开 ...

  2. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  3. 【BZOJ-4127】Abs 树链剖分 + 线段树 (有趣的姿势)

    4127: Abs Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 381  Solved: 132[Submit][Status][Discuss] ...

  4. BZOJ 3083 遥远的国度 树链剖分

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 797  Solved: 181[Submit][Status] Descrip ...

  5. BZOJ 2157: 旅游( 树链剖分 )

    树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...

  6. BZOJ 3083: 遥远的国度(树链剖分+DFS序)

    可以很显而易见的看出,修改就是树链剖分,而询问就是在dfs出的线段树里查询最小值,但由于这道题会修改根节点,所以在查询的时候需判断x是否为root的祖先,如果不是就直接做,是的话应该查询从1-st[y ...

  7. BZOJ 2157 旅行(树链剖分码农题)

    写了5KB,1发AC... 题意:给出一颗树,支持5种操作. 1.修改某条边的权值.2.将u到v的经过的边的权值取负.3.求u到v的经过的边的权值总和.4.求u到v的经过的边的权值最大值.5.求u到v ...

  8. BZOJ 3083 遥远的国度(树链剖分+LCA)

    Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...

  9. 【bzoj4127】Abs 树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

随机推荐

  1. hdu 1093 A+B for Input-Output Practice (V)

    A+B for Input-Output Practice (V) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3276 ...

  2. 世界上最方便的SharePoint移动客户端--Rshare

    Rshare我试用了一段时间,同时也测试了其他家产品,使用后的感觉是Rshare无愧于世界上最方面的SharePoint移动客户端. 1.界面设计很方便,设计中充分考虑到移动客户的使用习惯及喜好,设计 ...

  3. PHP之基本语法

    人生最幸福的事之一就是,邻居家的wifi密码是123456789,于是回家在pad上也照样可以扯淡.任何语言都有自己的语法,这里只简单说些我觉得应该注意的地方. 首先要明白,PHP是运行于服务器端的脚 ...

  4. 【转载】最近在用Arrays的asList()生成的List时,List元素的个数时而不正确,数组转化为List,即Arrays.asList(intArray);

    最近在用Arrays的asList()生成的List时,List元素的个数时而不正确. Java代码 //经多次测试,只要传递的基本类型的数组,生成List的元素个数均为1 char arrc = { ...

  5. linux---基本查找命令

    基本查找命令 一.文件查找命令:find 最大特点:功能强大,可以使用文件的各种属性作为查找条件来查找文件 文件属性:文件权限.文件所有者.文件大小.修改时间.文件类型 语法:find[起始查找目录] ...

  6. 一个类似repo的小程序

    #! /usr/bin/env python # -*- coding: utf-8 -*- # usage : python EasyRepo.py -u "13051041" ...

  7. Android之 Fragment

    什么是Fragment: Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局, ...

  8. (poj)1806 Currency Exchange

    题目链接:http://poj.org/problem?id=1860 Description Several currency exchange points are working in our ...

  9. VC++ CTime Format 详解

    参考链接: VC++中CTime类Format参数详解 CTime/COleDateTime::Format方法的使用 http://stat.ethz.ch/R-manual/R-devel/lib ...

  10. 信息收集->DNS分析->dnsdict6

    如何获取域名的IPV4/IPV6地址之dnsdict6的使用 dnsdict6是一个用于获取网站信息的工具.dnsdict6可以扫描网站并显示有多少域或者子域,也可以扫描ipv6/ipv4地址.dns ...