问题描述

LG4556


题解

对于每一个结点,建立一棵动态开点线段树。

然后自低向上合并线段树。

同时维护整个值域的最大值和最大值位置。


\(\mathrm{Code}\)

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. template <typename Tp>
  4. void read(Tp &x){
  5. x=0;char ch=1;int fh;
  6. while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
  7. if(ch=='-') ch=getchar(),fh=-1;
  8. else fh=1;
  9. while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
  10. x*=fh;
  11. }
  12. const int maxn=1000007;
  13. const int maxm=2000007;
  14. int n,m;
  15. int Head[maxn],Next[maxm],to[maxm],tot;
  16. int size[maxn],fa[maxn],son[maxn];
  17. int dep[maxn],top[maxn],du[maxn];
  18. void add(int x,int y){
  19. to[++tot]=y,Next[tot]=Head[x],Head[x]=tot;
  20. }
  21. void dfs1(int x,int f,int dp){
  22. size[x]=1,fa[x]=f,dep[x]=dp;
  23. int mx=-1;
  24. for(int i=Head[x];i;i=Next[i]){
  25. int y=to[i];
  26. if(y==f) continue;
  27. dfs1(y,x,dp+1);size[x]+=size[y];
  28. if(size[y]>mx) mx=size[y],son[x]=y;
  29. ++du[x];
  30. }
  31. }
  32. void dfs2(int x,int tp){
  33. top[x]=tp;
  34. if(!son[x]) return;
  35. dfs2(son[x],tp);
  36. for(int i=Head[x];i;i=Next[i]){
  37. int y=to[i];
  38. if(y==fa[x]||y==son[x]) continue;
  39. dfs2(y,y);
  40. }
  41. }
  42. int lca(int x,int y){
  43. while(top[x]!=top[y]){
  44. if(dep[top[x]]<dep[top[y]]) swap(x,y);
  45. x=fa[top[x]];
  46. }
  47. if(dep[x]>dep[y]) swap(x,y);
  48. return x;
  49. }
  50. int L[maxn*22],R[maxn*22];
  51. int rt[maxn],val[maxn*22],pos[maxn*22];
  52. int cnt;
  53. void pushup(int x){
  54. val[x]=max(val[L[x]],val[R[x]]);
  55. if(val[x]<=0) return;
  56. if(val[x]==val[L[x]]) pos[x]=pos[L[x]];
  57. else pos[x]=pos[R[x]];
  58. }
  59. int insert(int x,int l,int r,int p,int v){
  60. if(!x) x=++cnt;
  61. if(l==r){
  62. val[x]+=v,pos[x]=l;
  63. return x;
  64. }
  65. int mid=(l+r)>>1;
  66. if(p<=mid) L[x]=insert(L[x],l,mid,p,v);
  67. else R[x]=insert(R[x],mid+1,r,p,v);
  68. pushup(x);
  69. return x;
  70. }
  71. int ans[maxn];
  72. int merge(int p,int q,int l,int r){
  73. if(!p||!q) return p+q;
  74. if(l==r){
  75. val[q]+=val[p],pos[q]=l;
  76. return q;
  77. }
  78. int mid=(l+r)>>1;
  79. L[q]=merge(L[p],L[q],l,mid);
  80. R[q]=merge(R[p],R[q],mid+1,r);
  81. pushup(q);
  82. return q;
  83. }
  84. int main(){
  85. read(n);read(m);
  86. for(int i=1,x,y;i<n;i++){
  87. read(x);read(y);
  88. add(x,y);add(y,x);
  89. }
  90. dfs1(1,0,1);dfs2(1,1);
  91. for(int i=1;i<=n;i++) rt[i]=++cnt;
  92. for(int i=1,x,y,z;i<=m;i++){
  93. read(x);read(y);read(z);
  94. int LCA=lca(x,y);
  95. insert(rt[x],1,100000,z,1);
  96. insert(rt[y],1,100000,z,1);
  97. insert(rt[LCA],1,100000,z,-1);
  98. insert(rt[fa[LCA]],1,100000,z,-1);
  99. }
  100. queue<int>q;
  101. for(int i=1;i<=n;i++){
  102. if(!du[i]) q.push(i);
  103. }
  104. while(!q.empty()){
  105. int x=q.front();q.pop();
  106. ans[x]=pos[rt[x]];
  107. merge(rt[x],rt[fa[x]],1,100000);
  108. --du[fa[x]];
  109. if(!du[fa[x]]) q.push(fa[x]);
  110. }
  111. for(int i=1;i<=n;i++){
  112. printf("%d\n",ans[i]);
  113. }
  114. return 0;
  115. }

LG4556 [Vani有约会]雨天的尾巴 动态开点线段树+线段树合并的更多相关文章

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

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

  2. P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)

    P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...

  3. 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告

    P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...

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

    P4556 [Vani有约会]雨天的尾巴 题意: 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋 ...

  5. 「Luogu4556」Vani有约会-雨天的尾巴

    「Luogu4556」Vani有约会-雨天的尾巴 传送门 很显然可以考虑树上差分+桶,每次更新一条链就是把这条链上的点在桶对应位置打上 \(1\) 的标记, 最后对每个点取桶中非零值的位置作为答案即可 ...

  6. [题解] P4556 [Vani有约会]雨天的尾巴

    [题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...

  7. [Vani有约会]雨天的尾巴——树上差分+动态开点线段树合并

    题目描述 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮. 然后深绘里想知道,当所 ...

  8. P4556 [Vani有约会]雨天的尾巴

    目录 思路 优化 过程中的问题/疑问 错误 代码 思路 每个节点维护一课线段树(当然是动态开点) 线段树的作用是统计这个节点有多少种粮食型号,以及最多的粮食型号 然后树上差分,u和v点 +1,lca( ...

  9. P4556 [Vani有约会]雨天的尾巴(线段树合并)

    传送门 一道线段树合并 首先不难看出树上差分 我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可 然而问题就在 ...

随机推荐

  1. springmvc 什么时候 set applicationContext 到 ServletConfig 的?

    springmvc 什么时候 set applicationContext 到 ServletConfig 的? FrameworkServlet --> initWebApplicationC ...

  2. flask之请求与响应、闪现(阅后即焚)、请求扩展(before,after)、中间件、LOCAL对象、偏函数、

    目录 1.flask请求与响应 2.闪现 3.请求扩展 4.中间件 5.LOCAL对象 6.偏函数 templates 1.flask请求与响应 from flask import Flask,req ...

  3. 学习workerman之前需要知道的几种php回调写法

    在workerman中会经常使用,我们先写一个回调函数,当某个行为被触发后使用该函数处理相关逻辑. 在PHP中最常用的几种回调写法如下 匿名函数做为回调 匿名函数(Anonymous function ...

  4. Sublime和VSCode生成基础HTML代码

    我们在编写前端页面时,常希望能自动生成基础的HTML代码.而在Sublime和VSCode就有这样的功能 在Sublime中,在编辑栏输入html,然后敲Tab键,则自动生成代码如下: <!DO ...

  5. 《细说PHP》第四版 样章 第23章 自定义PHP接口规范 2

    23.1.3  接口的应用和优势 API是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无须访问源码,或理解内部工作机制的细节.接口应用的一些常见场景如下 ...

  6. 纯手打AJAX,还有一个对象转查询字符串的小方法obj=>url

    function json2url(json){ var arr=[]; for(var name in json){ arr.push(name+'='+json[name]); } return ...

  7. 动态SQL屏幕条件选择(里面还有赋值的新语法)

    有时候屏幕条件中使用PARAMETERS时候,如果你为空的话,会查不出数据,但是可能你的想法是不想限制而已,但是系统默认理解为了空值,这个时候,如果取判断一下条件是不是空,在SQL里决定写不写的话,会 ...

  8. 全栈工程师对Python面试中is和==区别的详细解说!看完真的学到了!

    面试实习生的时候,当问到 is 和 == 的区别时,很多同学都答不上来,搞不清两者什么时候返回一致,什么时候返回不一致.本文我们来看一下这两者的区别. 我们先来看几个例子: a = "hel ...

  9. Rpg maker mv角色扮演游戏制作大师简介

    目录 1:简介 2:基本图片展示 3.和js等平台的合作 @(这里写自定义目录标题) 1:简介   <RPG制作大师MV>为<RPG制作大师>的新版本,于18年11月27日登陆 ...

  10. 在Vue-cli3.x中引入element-ui的新方式

    今天登上element官网,发现element对vue-cli3.x的项目做了特殊定制: 这意味着即使是按需引入,也无需像过去那样手动安装babel-plugin-component,配置babel. ...