题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D。

  做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以x为第一个数字的不下降子序列中第i个数的最小值,MX[i]表示以x为第一个数字的不上升子序列中第i个数的最大值。如果当前子树有一个以x为首的不下降序列,那么我们就需要在之前处理的子树中找一条以x为首的满足约束条件不上升序列,可以用线段树来查询。同时每做完一颗子树的时候,用MN,MX对线段树进行更新。对于不经过x的情况可以递归下去处理。

  代码:

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #define N 1000010
  5. using namespace std;
  6. int dp,p[N],s[N],pre[N],tt[N],flag[N],father[N],tmproot,n,d,ttt;
  7. int i,v[N],a,b,mn,mx,MN[N],MX[N],U,V,ans;
  8. int l[N],r[N],smn[N],smx[N],vsmn[N],vsmx[N];
  9. void build(int x,int a,int b)
  10. {
  11. int m;
  12. l[x]=a;r[x]=b;
  13. if (x>ttt) ttt=x;
  14. if (b-a>)
  15. {
  16. m=(a+b)>>;
  17. build(*x,a,m);
  18. build(*x+,m,b);
  19. }
  20. }
  21. void clean(int x)
  22. {
  23. if (vsmn[x])
  24. {
  25. smn[x]=;
  26. if (*x<=ttt)
  27. vsmn[*x]=;
  28. if (*x+<=ttt)
  29. vsmn[*x+]=;
  30. vsmn[x]=;
  31. }
  32.  
  33. if (vsmx[x])
  34. {
  35. smx[x]=;
  36. if (*x<=ttt)
  37. vsmx[*x]=;
  38. if (*x+<=ttt)
  39. vsmx[*x+]=;
  40. vsmx[x]=;
  41. }
  42. }
  43. void change(int x,int a,int b,int c,int typ)
  44. {
  45. int m;
  46. clean(x);
  47. if ((a<=l[x])&&(r[x]<=b))
  48. {
  49. if (typ==)
  50. smn[x]=max(smn[x],c);
  51. else
  52. smx[x]=max(smx[x],c);
  53. return;
  54. }
  55. m=(l[x]+r[x])>>;
  56. if (a<m) change(*x,a,b,c,typ);
  57. if (m<b) change(*x+,a,b,c,typ);
  58. clean(*x);clean(*x+);
  59. if (!typ)
  60. smn[x]=max(smn[*x],smn[*x+]);
  61. else
  62. smx[x]=max(smx[*x],smx[*x+]);
  63. }
  64. int query(int x,int a,int b,int typ)
  65. {
  66. int m,ans=;
  67. clean(x);
  68. if ((a<=l[x]&&(r[x]<=b)))
  69. {
  70. if (typ==)
  71. return smn[x];
  72. else
  73. return smx[x];
  74. }
  75. m=(l[x]+r[x])>>;
  76. if (a<m) ans=max(ans,query(*x,a,b,typ));
  77. if (m<b) ans=max(ans,query(*x+,a,b,typ));
  78. return ans;
  79. }
  80. void link(int x,int y)
  81. {
  82. dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
  83. }
  84. int getroot(int x,int fa,int sum)
  85. {
  86. int i,f=;
  87. i=p[x];
  88. father[x]=fa;
  89. s[x]=;
  90. while (i)
  91. {
  92. if ((tt[i]!=fa)&&(!flag[tt[i]]))
  93. {
  94. getroot(tt[i],x,sum);
  95. s[x]=s[x]+s[tt[i]];
  96. if (s[tt[i]]>sum/) f=;
  97. }
  98. i=pre[i];
  99. }
  100. if (sum-s[x]>sum/) f=;
  101. if (!f) tmproot=x;
  102. }
  103. void dfs(int x,int fa,int mn,int mx)
  104. {
  105. int i;
  106. i=p[x];
  107. if (v[x]>=v[fa])
  108. {
  109. if (mn)
  110. {
  111. mn++;
  112. MN[mn]=min(MN[mn],v[x]);
  113. }
  114. if (v[x]>v[fa])
  115. mx=;
  116. }
  117. if (v[x]<=v[fa])
  118. {
  119. if (mx)
  120. {
  121. mx++;
  122. MX[mx]=max(MX[mx],v[x]);
  123. }
  124. if (v[x]<v[fa])
  125. mn=;
  126. }
  127. U=max(U,mn);
  128. V=max(V,mx);
  129. while (i)
  130. {
  131. if ((tt[i]!=fa)&&(!flag[tt[i]]))
  132. dfs(tt[i],x,mn,mx);
  133. i=pre[i];
  134. }
  135. }
  136. void work(int x,int sum)
  137. {
  138. int i,j,k,root;
  139. getroot(x,,sum);
  140. root=tmproot;
  141. i=p[root];
  142. flag[root]=;
  143. while (i)
  144. {
  145. if (flag[tt[i]]==)
  146. {
  147. if (tt[i]==father[root])
  148. work(tt[i],sum-s[root]);
  149. else
  150. work(tt[i],s[tt[i]]);
  151. }
  152. i=pre[i];
  153. }
  154. //------------------------------
  155. i=p[root];
  156. vsmn[]=;
  157. vsmx[]=;
  158. while (i)
  159. {
  160. if (!flag[tt[i]])
  161. {
  162. for (j=;j<=U;j++)
  163. MN[j]=0x37373737;
  164. for (j=;j<=V;j++)
  165. MX[j]=;
  166. U=;V=;
  167. dfs(tt[i],root,,);
  168. for (j=;j<=U;j++)
  169. {
  170. if (MN[j]-d<=v[root])
  171. ans=max(ans,j);
  172. k=MN[j]-d;
  173. if (k<) k=;
  174. if (k<=v[root])
  175. ans=max(ans,j+query(,k-,v[root],)-);
  176. }
  177. for (j=;j<=V;j++)
  178. {
  179. if (MX[j]+d>=v[root])
  180. ans=max(ans,j);
  181. k=MX[j]+d;
  182. if (k>) k=;
  183. if (k>=v[root])
  184. ans=max(ans,j+query(,v[root]-,k,)-);
  185. }
  186.  
  187. for (j=;j<=U;j++)
  188. change(,MN[j]-,MN[j],j,);
  189. for (j=;j<=V;j++)
  190. change(,MX[j]-,MX[j],j,);
  191. }
  192. i=pre[i];
  193. }
  194. flag[root]=;
  195. }
  196. int main()
  197. {
  198. build(,,);
  199. for (i=;i<=;i++)
  200. MN[i]=0x37373737;
  201. int test,ii=;
  202. scanf("%d",&test);
  203. while (test)
  204. {
  205. test--;
  206. ii++;
  207. dp=;memset(p,,sizeof(p));
  208. scanf("%d%d",&n,&d);
  209. for (i=;i<=n;i++)
  210. scanf("%d",&v[i]);
  211. for (i=;i<=n-;i++)
  212. {
  213. scanf("%d%d",&a,&b);
  214. link(a,b);
  215. link(b,a);
  216. }
  217. ans=;
  218. work(,n);
  219. printf("Case #%d: %d\n",ii,ans);
  220. }
  221. }

UVALive 7148 LRIP【树分治+线段树】的更多相关文章

  1. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...

  2. LOJ#6463 AK YOI 树分治+线段树合并

    传送门 既然是树上路径统计问题,不难想到要使用树分治,这里以点分治为例 由点分治的性质,每层只需要考虑经过重心的路径 因为需要维护路径长度在一定范围内的最大权值和,所以要用一个数据结构维护一下到根节点 ...

  3. 【BZOJ3730】震波 动态树分治+线段树

    [BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土 ...

  4. 7.18 NOI模拟赛 因懒无名 线段树分治 线段树维护直径

    LINK:因懒无名 20分显然有\(n\cdot q\)的暴力. 还有20分 每次只询问一种颜色的直径不过带修改. 容易想到利用线段树维护直径就可以解决了. 当然也可以进行线段树分治 每种颜色存一下直 ...

  5. bzoj3730 [震波][动态树分治+线段树+LCA]

    震波 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 1573  Solved: 358[Submit][Status][Discuss] Descri ...

  6. BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)

    题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...

  7. 【loj6145】「2017 山东三轮集训 Day7」Easy 动态点分治+线段树

    题目描述 给你一棵 $n$ 个点的树,边有边权.$m$ 次询问,每次给出 $l$ .$r$ .$x$ ,求 $\text{Min}_{i=l}^r\text{dis}(i,x)$ . $n,m\le ...

  8. 【bzoj4372】烁烁的游戏 动态点分治+线段树

    题目描述 给一颗n个节点的树,边权均为1,初始点权均为0,m次操作:Q x:询问x的点权.M x d w:将树上与节点x距离不超过d的节点的点权均加上w. 输入 第一行两个正整数:n,m接下来的n-1 ...

  9. 【bzoj3730】震波 动态点分治+线段树

    题目描述 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土地常常发生地震,并且随着时代的发展,城市 ...

随机推荐

  1. 超简单的处理JSON格式和JSON数组格式的String

    现在网站上有不少处理JSON格式的工具类,但是我找了一天,发现大都是需要编写相应对象类来进行处理,比较麻烦,比如:Gson,json-lib.Gson,json-lib这些处理那些接口之类的参数名字和 ...

  2. VS附加到进程调试的方法及应用场景

    应用场景:.Net做网站时,代码量很大的时候,每次调试一个网页都编译整个网站是不显示的,而且有时候整个网站是存在错误的,通不过编译.这时你又要调试某部分网页,就可以通过附加到进程调试.方法如下: (1 ...

  3. session和cookie区别

    <?php session_start(); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//E ...

  4. docker confluence

    http://wuyijun.cn/shi-yong-dockerfang-shi-an-zhuang-he-yun-xing-confluence/ https://hub.docker.com/r ...

  5. Java实验报告五:Java网络编程及安全

    Java实验报告五:Java网络编程及安全                                                                               ...

  6. 转:Windows Socket五种I/O模型

    原文转自:  Windows Socket五种I/O模型 Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模 ...

  7. php--yii2.0框架的curl

    yii2.0框架的增删改查 //插入操作  save() $customer=new Customer(); $customer->name=‘小熊‘; $customer->save() ...

  8. [LeetCode] Substring with Concatenation of All Words(good)

    You are given a string, S, and a list of words, L, that are all of the same length. Find all startin ...

  9. backbone extend 源码分析

    var extend = function(protoProps, staticProps) { var parent = this; var child; if (protoProps && ...

  10. http://blog.csdn.net/littlechang/article/details/8642149

    http://blog.csdn.net/littlechang/article/details/8642149