题目链接


解题思路:

  1. 首先题目是对u,vu,vu,v这两条路径上面添加一个zzz,然后运用树上点的差分思想,对于分发路径u,vu,vu,v,我们在uuu上+1+1+1,在vvv上+1+1+1,在lca(u,v)lca(u,v)lca(u,v)处−1-1−1,在fa(lca)fa(lca)fa(lca)处−1-1−1,最后统计时自底向上做树上前缀和
  2. 但是每次加的种类不一样,使用线段树合并,每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号(下标)。所以每个节点答案即为。
  3. 代码有详细注释:
  4. 空间大小:maxn∗log2(4∗maxm)≤70maxn * log_2(4*maxm) \leq70maxn∗log2​(4∗maxm)≤70


AC代码

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 100010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}
int fa[maxn][20], depth[maxn];
int n, m;
vector<int> G[maxn];
void dfs(int u, int f) {depth[u] = depth[f] + 1;fa[u][0] = f;for(int i = 1; i < 20; ++ i)fa[u][i] = fa[fa[u][i-1]][i-1];for(auto it : G[u]) {if(it == f) continue;dfs(it,u);}
}
inline int LCA(int x, int y) {//求LCAif(depth[x] < depth[y]) swap(x,y);int delta = depth[x] - depth[y];for(int i = 19; i >= 0; -- i)if(delta >> i & 1)x = fa[x][i];if(x == y) return x;for(int i = 19; i >= 0; -- i)if(fa[x][i] != fa[y][i])x = fa[x][i], y = fa[y][i];return fa[x][0];
}
//....................................
struct Segtree {int l, r;PII val;//第一维个数 ,第二位维度
}sgt[maxn * 70];
int root[maxn], cnt;PII &max(PII &a, PII &b) {//重新定义max函数在有相同的个数时候取编号小的if(a.first > b.first) return a;else if(a.first == b.first) return a.second < b.second ? a : b;else return b;
}void pushup(int rt) {sgt[rt].val = max(sgt[sgt[rt].l].val,sgt[sgt[rt].r].val);
}void modify(int &rt, int l, int r, int pos, int val) {if(!rt) rt = ++ cnt;//每次修改开节点if(l == r) sgt[rt].val.first += val, sgt[rt].val.second = pos;else {if(pos <= mid) modify(sgt[rt].l,l,mid,pos,val);else modify(sgt[rt].r,mid+1,r,pos,val);pushup(rt);}
}void merge(int &x, int y, int l = 1, int r = maxn) {if(!x || !y) x |= y;else if(l == r) sgt[x].val.first += sgt[y].val.first, sgt[x].val.second = l;else {merge(sgt[x].l,sgt[y].l,l,mid);merge(sgt[x].r,sgt[y].r,mid+1,r);pushup(x);}
}
int ans[maxn];
void dfs1(int u) {for(auto it : G[u]) {if(it == fa[u][0]) continue;dfs1(it);merge(root[u],root[it]);//合并}if(sgt[root[u]].val.first) ans[u] = sgt[root[u]].val.second;
}int main() {IOS;cin >> n >> m;for(int i = 1; i <= n - 1; ++ i) {int u, v;cin >> u >> v;G[u].push_back(v);G[v].push_back(u);}dfs(1,0);while(m --) {int u, v, z;cin >> u >> v >> z;//4次差分合并所以上面是4*maxm!!modify(root[u],1,maxn,z,1);modify(root[v],1,maxn,z,1);modify(root[LCA(u,v)],1,maxn,z,-1);modify(root[fa[LCA(u,v)][0]],1,maxn,z,-1);}dfs1(1);for(int i = 1; i <= n; ++ i)cout << ans[i] << endl;return 0;
}

线段树分裂与合并 ---- 树上差分 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并相关推荐

  1. 洛谷 - P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并(树上差分+线段树合并)

    题目链接:点击查看 题目大意:给出一棵树,再给出 m 次操作,每次操作会选择两个点 ( x , y ) ,使得这条路径上的所有点的种类 z 加一,最后问每个点的哪个种类出现的频率最高,若多个种类出现频 ...

  2. 洛咕 P4556 [Vani有约会]雨天的尾巴

    终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...

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

    题目链接 Solution 树上差分+线段树合并. 在每个节点上维护一棵权值线段树. 然后如果需要修改 \(x,y\) 两点,则在 \(x\) 处和 \(y\) 处分别加上 \(1\) 的权值. 然后 ...

  4. 雨中的尾巴(线段树合并+树上差分)

    哇这道题 恶心死我 首先要知道,树上差分一般解决的问题是关于树上的覆盖问题 然后遇到覆盖问题尽量不要打树剖(会慢很多) 关于此题 因为这道题覆盖的是 从xxx到yyy的点 所以我们在 x,yx,yx, ...

  5. BZOJ4771 七彩树(dfs序+树上差分+主席树)

    考虑没有深度限制怎么做.显然的做法是直接转成dfs序上主席树,但如果拓展到二维变成矩形数颜色数肯定没法做到一个log. 另一种做法是利用树上差分.对于同种颜色的点,在每个点处+1,dfs序相邻点的lc ...

  6. 【线段树合并】解题报告:luogu P4556雨天的尾巴 (树上对点差分 + 动态开点 + 线段树合并)线段树合并模板离线/在线详解

    题目链接:雨天的尾巴 本题本身是一个非常简单的一道树上差分的模板题,但是由于变态的数据范围,我们直接用数组是存不下的(本来使用一颗普通的线段树直接维护最大值即可.但是本题的空间只有128MB,直接按照 ...

  7. 【NOIP2016】【桶/线段树合并】【树上差分】天天爱跑步

    [题目描述] [思路] 这是道好题呀.考虑把一条路径(u,v)拆成两条:从u到lca(u,v),从lca(u,v)到v.下面我们以向上的路径为例讨论做法.对于一条向上的路径,它对一个点x有贡献当且仅当 ...

  8. 模版:线段树合并+线段树分裂

    文章目录 前言 合并 代码 分裂 代码 前言 话说天下之树,分久必合,合久必分 合并 所谓合并,就是把两个树合并 以把B树合并到A树为例 如果A没有该节点,改成B的该节点返回 如果B没有该节点,直接返 ...

  9. P4556,jzoj3397-[GDOI2014模拟]雨天的尾巴【树链剖分,线段树】

    正题 题目链接:https://www.luogu.org/problemnew/show/P4556 题目大意 nnn个点的一棵树,给出mmm个操作(x,y,z)(x,y,z)(x,y,z)表示将x ...

最新文章

  1. HelloX项目github协同开发指南
  2. HBase 与Hive数据交互整合过程详解
  3. verilog 简单module_一个简单的verilog小程序
  4. IDEA中maven如何将jar包导入本地的maven库
  5. java高并发类_Java 高并发之魂
  6. DFS VS BFS
  7. 版本控制工具——Git常用操作(上)
  8. 有关MATLAB归一化处理中,mapminmax的用法详解
  9. QQ群排名优化规则-学会后10分钟全国排名第一
  10. php呼叫平台,php – Twilio呼叫转发
  11. VMware虚拟机下Ubuntu18.04学校宽带拨号连接网络
  12. android5去wifi感叹号,android 5.1 WIFI图标上的感叹号及其解决办法
  13. 以太坊+IPFS+WEB 电商平台开发讲解
  14. 一条双字长的取数指令(LDA)存于存储器的100和101单元,其中第一个字为操作码和寻址特征M,第二个字为形式地址。
  15. 【数据结构】最小生成树(Prim算法,普里姆算法,普利姆)、最短路径(Dijkstra算法,迪杰斯特拉算法,单源最短路径)
  16. 记一次服务器负载飙高排查过程
  17. 虚拟机vmare安装CentOS7详细教程
  18. [乡土民间故事_徐苟三传奇]第十六回_差狗子认输吃大粪
  19. LXC是什么、什么是docker、docker产生的背景
  20. 磨人的小妖精 别让我遇到你

热门文章

  1. python使用PyMySQL的连接MySQL数据库
  2. VUE的本地应用-V- on
  3. linux系统版本间的区别是什么?内核又是什么
  4. Linux综合大作业
  5. 如何使用 OpenCV 开发虚拟键盘
  6. Batch Normalization应该放在ReLU非线性激活层的前面还是后面?
  7. 我用python10年后,我发现学python必看这三本书! 1
  8. Swift 面向对象
  9. springmvc+quartz简单实现定时调度
  10. ANT无线通信技术(2) 通道配置