C. 雨天的尾巴

题目描述

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。

输入格式

第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题

输出格式

输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出0

样例

样例输入

  1.  

样例输出

  1.  

数据范围与提示

1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10910^910​9​​

暴力能得50分呢……

树上操作首先会想到树剖和树上差分吧,这里只说差分;

离线处理,权值线段树维护每一个点的状态(每种物品出现次数及其最大值),对于每次操作,将x+1,y+1,LCA(x,y)-1,fa[LCA]-1最后dfs合并线段树统计答案即可。

注意合并(修改)叶子节点时最大值是加而不是取max。

这道题比较恶心的是卡内存,卡了我四节课…

如果线段树合并操作是建新节点的话会MLE,代码如下:

  1. int merge(int x,int y)
  2. {
  3. if(!x||!y)return x+y;
  4. int now=++cnt;
  5. sum(now)=sum(x)+sum(y);
  6. l(now)=merge(l(x),l(y));
  7. r(now)=merge(r(x),r(y));
  8. if(!l(x) && !r(x))maxn(now)=maxn(x)+maxn(y);
  9. else maxn(now)=max( maxn(l(now)) , maxn(r(now)) );
  10. return now;
  11. }

但是显然不这样的话数据会出错(将y的子树同时变为x的子树,之后在合并x时会修改数据),但是其实并不需要让线段树最后是正确的,只需要在y数据发生错误之前记录答案即可。

标程

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<map>
  4. #include<time.h>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. using namespace std;
  8. struct edge
  9. {
  10. int u,v,next;
  11. #define u(x) ed[x].u
  12. #define v(x) ed[x].v
  13. #define n(x) ed[x].next
  14. }ed[];
  15. int first[],num_e;
  16. #define f(x) first[x]
  17. int n,m,Q,fa[][],bin[],dep[];
  18. int x[],y[],z[],z2[];
  19. map<int,int> mp;
  20. int mmp[];
  21. int ans[];
  22.  
  23. struct tree
  24. {
  25. int l,r,sum,maxn;
  26. #define l(x) tr[x].l
  27. #define r(x) tr[x].r
  28. #define sum(x) tr[x].sum
  29. #define maxn(x) tr[x].maxn
  30. }tr[];
  31. int cnt,rt[];
  32.  
  33. int ask(int l,int r,int a)
  34. {
  35. if(sum(a)==)return ;
  36. if(l==r)return l;
  37. int mid=(l+r)>>;
  38. if(maxn(l(a))>=maxn(r(a)))return ask(l,mid,l(a));
  39. return ask(mid+,r,r(a));
  40. }
  41. void add(int &mark,int l,int r,int loc,int val)
  42. {
  43. if(!mark)mark=++cnt;
  44. if(l==r){sum(mark)+=val;maxn(mark)+=val;return;}
  45. int mid=(l+r)>>;
  46. if(loc<=mid)add(l(mark),l,mid,loc,val);
  47. else add(r(mark),mid+,r,loc,val);
  48. sum(mark)=sum(l(mark))+sum(r(mark));
  49. maxn(mark)=max( maxn(l(mark)) , maxn(r(mark)));
  50. }
  51. int merge(int x,int y)
  52. {
  53. if(!x||!y)return x+y;
  54. l(x)=merge(l(x),l(y));
  55. r(x)=merge(r(x),r(y));
  56. sum(x)=sum(x)+sum(y);
  57. if(!l(x) && !r(x))maxn(x)=maxn(x)+maxn(y);
  58. else maxn(x)=max( maxn(l(x)) , maxn(r(x)) );
  59. return x;
  60. }
  61. void dfs2(int x,int ffa);
  62. inline int read();
  63. int LCA(int x,int y);
  64. void dfs(int x,int ffa);
  65. inline void add_e(int u,int v);
  66. signed main()
  67. {
  68. // freopen("4.in","r",stdin);
  69. // freopen("out.txt","w",stdout);
  70.  
  71. bin[]=;
  72. for(int i=;i<=;i++)bin[i]=bin[i-]*;
  73. n=read(),Q=read();
  74. int ta,tb;
  75. for(int i=;i<n;i++)
  76. {
  77. ta=read(),tb=read();
  78. add_e(ta,tb);
  79. add_e(tb,ta);
  80. }
  81. for(int j=;j<=Q;j++)
  82. x[j]=read(),y[j]=read(),z[j]=read(),z2[j]=z[j];
  83. sort(z2+,z2+Q+);
  84. m=unique(z2+,z2+Q+)-z2-;
  85. for(int i=;i<=Q;i++)
  86. {
  87. int loc=lower_bound(z2+,z2+m+,z[i])-z2;
  88. mp[z[i]]=loc;
  89. mmp[loc]=z[i];
  90. }
  91. dfs(,);
  92. for(int j=;j<;j++)
  93. for(int i=;i<=n;i++)
  94. fa[i][j]=fa[fa[i][j-]][j-];
  95. mmp[]=;
  96. for(int i=;i<=Q;i++)
  97. {
  98. int loc=mp[z[i]],
  99. lca=LCA(x[i],y[i]),
  100. ffa=fa[lca][];
  101. add(rt[x[i]],,m,loc,);
  102. add(rt[y[i]],,m,loc,);
  103. add(rt[lca], ,m,loc,-);
  104. if(ffa)
  105. add(rt[ffa] ,,m,loc,-);
  106. }
  107. dfs2(,);
  108. ans[]=ask(,m,rt[]);
  109. for(int i=;i<=n;i++)
  110. printf("%d\n",mmp[ans[i]]);
  111. }
  112. void dfs2(int x,int ffa)
  113. {
  114. for(int i=f(x);i;i=n(i))
  115. if(v(i)!=ffa)
  116. {
  117. dfs2(v(i),x);
  118. ans[v(i)]=ask(,m,rt[v(i)]);
  119. rt[x]=merge(rt[x],rt[v(i)]);
  120. }
  121. }
  122. inline int read()
  123. {
  124. int s=;char a=getchar();
  125. while(a<''||a>'')a=getchar();
  126. while(a>=''&&a<=''){s=s*+a-'';a=getchar();}
  127. return s;
  128. }
  129. inline void add_e(int u,int v)
  130. {
  131. ++num_e;
  132. u(num_e)=u;
  133. v(num_e)=v;
  134. n(num_e)=f(u);
  135. f(u)=num_e;
  136. }
  137. void dfs(int x,int ffa)
  138. {
  139. fa[x][]=ffa;
  140. dep[x]=dep[ffa]+;
  141. for(int i=f(x);i;i=n(i))
  142. if(v(i)!=ffa)
  143. dfs(v(i),x);
  144. }
  145. int LCA(int x,int y)
  146. {
  147. if(dep[x]>dep[y])swap(x,y);
  148. while(dep[x]!=dep[y])
  149. for(int i=;;i++)
  150. if(dep[fa[y][i]]<dep[x])
  151. {
  152. y=fa[y][i-];
  153. break;
  154. }
  155. if(x==y)return x;
  156. while(fa[x][]!=fa[y][])
  157. for(int i=;;i++)
  158. if(fa[x][i]==fa[y][i])
  159. {x=fa[x][i-],y=fa[y][i-];break;}
  160. return fa[x][];
  161. }

Bzoj 3307 雨天的尾巴(线段树合并+树上差分)的更多相关文章

  1. bzoj 3307: 雨天的尾巴 线段树合并

    题目大意: N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.问完成所有发放后,每个点存放最多的是哪种物品. 题解: 首先我们为每一个节 ...

  2. bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】

    这居然是我第一次写线段树合并--所以我居然在合并的时候加点结果WAWAWAMLEMLEMLE--!ro的时候居然直接指到la就行-- 树上差分,每个点建一棵动态开点线段树,然后统计答案的时候合并即可 ...

  3. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

  4. [Vani有约会]雨天的尾巴 线段树合并

    [Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...

  5. 【BZOJ3307】雨天的尾巴 线段树合并

    [BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...

  6. BZOJ3307雨天的尾巴——线段树合并

    题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入 第一行数字N,M接下来N ...

  7. 雨天的尾巴(bzoj3307)(线段树合并+树上差分)

    \(N\)个点,形成一个树状结构.有\(M\)次发放,每次选择两个点\(x,y\) 对于\(x\)到\(y\)的路径上(含\(x,y\))每个点发一袋\(Z\)类型的物品.完成 所有发放后,每个点存放 ...

  8. bzoj3307 雨天的尾巴 题解(线段树合并+树上差分)

    Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后,每个点存放最多的是哪种物品. Input ...

  9. P4556 雨天的尾巴 线段树合并

    使用线段树合并,每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号(下标).所以每个节点答案即为\(tre[rot[x]]\). 然后运用树上点的差分思想,对于分发路径\(u, ...

随机推荐

  1. cmath函数整理

    double a= pow(double x, double y)://返回x的y次方. double a= sqrt(double x)://返回x的平方根. double a=ceil(doubl ...

  2. Java ServerSocket的服务端代码介绍

    转自:http://developer.51cto.com/art/201003/190007.htm 所谓Java ServerSocket通常也称作"套接字",有不少的时候需要 ...

  3. bzoj 4245: [ONTAK2015]OR-XOR【按位贪心】

    知道按位贪心但是不知道怎么贪-- 求一个a的异或前缀和s,然后按位从大到小贪心,ans的当前位能为0的条件是s中有>=m个位置这一位为0且没有flag,并且s[n]的这一位为0 如果符合要求,那 ...

  4. 极简版OKEX比特币跨期对冲策略

    策略特点 只做正套,反套可以修改下,合约调换一下,即是反套. 添加两个 交易所对象,第一个季度,第二个当周. 精简了所有能简化的代码,优化空间还很大,教学策略谨慎实盘,跨期有一定风险. 欢迎反馈BUG ...

  5. 【POJ - 1661】Help Jimmy (动态规划)

    Help Jimmy Descriptions: "Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长 ...

  6. tableView 加载更多

    在ios开中中,由于屏幕尺寸限制,如果需要显示的数据很多,需要用到分页加载. 原理:先数据放到一个table中,先显示10条,table底部有一察看更多选项,点击察看更多查看解析的剩余数据.基本上就是 ...

  7. vijos1846 [NOIP2013] 华容道【最短路】

    传送门:https://vijos.org/p/1983 (其实noip的题各个oj都会有的,就不贴其它传送门了) 这道题真的是,怎么说,我都不知道怎么评价了= =.果然数据量小的题怎么暴力都可以过. ...

  8. 暴力 BestCoder Round #46 1001 YJC tricks time

    题目传送门 /* 暴力:模拟枚举每一个时间的度数 详细解释:http://blog.csdn.net/enjoying_science/article/details/46759085 期末考结束第一 ...

  9. 找规律 Codeforces Round #309 (Div. 2) A. Kyoya and Photobooks

    题目传送门 /* 找规律,水 */ #include <cstdio> #include <iostream> #include <algorithm> #incl ...

  10. 首先定义一个5X8的二维数组,然后使用随机数填充满。借助Arrays的方法对二维数组进行排序。

    package day02; import java.util.Arrays; import java.util.Random; public class Test01 { public static ...