P4556 [Vani有约会]雨天的尾巴 树链剖分 线段树合并
P4556 [Vani有约会]雨天的尾巴
提交记录 查看题解
标签
相关讨论
进入讨论版
推荐题目
题目背景
深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。
题目描述
首先村落里的一共有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。
输入输出样例
5 3 1 2 3 1 3 4 5 3 2 3 3 1 5 2 3 3 3
2 3 3 0 2
说明/提示
对于20%的数据,1 <= n, m <= 100
对于50%的数据,1 <= n, m <= 2000
对于100%的数据,1 <= n, m <= 100000, 1 <= a, b, x, y <= n, 1 <= z <= 100000
这题很明显是一道树剖题 但是可以用线段树合并来解决
显然每个点维护一个权值线段树 可以直接输出做多的粮食是什么
因为线段树合并自下而上类似一个求前缀和的过程 所以可以利用差分数组 点更新
在u+1 v+1 lca(u,v)-1 falca(u,v)-1 即可
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) // const int N=6000005;int T[N<<2],lson[N<<2],rson[N<<2],maxx[N<<2],t[N<<2],ncnt,n,m,nn,ans[N]; void up(int pos) {if(maxx[lson[pos]]>=maxx[rson[pos]])maxx[pos]=maxx[lson[pos]],t[pos]=t[lson[pos]];else maxx[pos]=maxx[rson[pos]],t[pos]=t[rson[pos]]; } void upnode(int x,int v,int l,int r,int &pos) {if(!pos)pos=++ncnt;if(l==r){t[pos]=l;maxx[pos]+=v;return ;}int m=(l+r)>>1;if(x<=m)upnode(x,v,l,m,lson[pos]);else upnode(x,v,m+1,r,rson[pos]);up(pos); } int Merge(int a,int b,int l,int r) {if(!a)return b;if(!b)return a;if(l==r){maxx[a]+=maxx[b];t[a]=l;return a;}int m=(l+r)>>1;lson[a]=Merge(lson[a],lson[b],l,m);rson[a]=Merge(rson[a],rson[b],m+1,r);up(a);return a; } int fa[N],top[N],siz[N],son[N],dep[N],pos,head[N]; struct Edge{int to,nex;}edge[N]; void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}void dfs1(int x,int f) {fa[x]=f;dep[x]=dep[f]+1;siz[x]=1;son[x]=0;for(int i=head[x];i;i=edge[i].nex){int v=edge[i].to;if(v==f)continue;dfs1(v,x);siz[x]+=siz[v];if(siz[son[x]]<siz[v])son[x]=v;} } void dfs2(int x,int topf) {top[x]=topf;if(son[x])dfs2(son[x],topf);for(int i=head[x];i;i=edge[i].nex){int v=edge[i].to;if(v==fa[x]||v==son[x])continue;dfs2(v,v);} } int Lca(int x,int y) {while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);x=fa[top[x]];}return dep[x]<dep[y]?x:y; } void dfs3(int x) {for(int i=head[x];i;i=edge[i].nex)if(dep[edge[i].to]>dep[x])dfs3(edge[i].to),T[x]=Merge(T[x],T[edge[i].to],1,nn);if(maxx[T[x]])ans[x]=t[T[x]]; } int L[N],R[N],V[N]; int main() {cin>>n>>m;rep(i,1,n-1){int x,y;scanf("%d%d",&x,&y);add(x,y);add(y,x);}rep(i,1,n)T[i]=i,++ncnt;dfs1(1,0);dfs2(1,1);rep(i,1,m){scanf("%d%d%d",&L[i],&R[i],&V[i]);nn=max(nn,V[i]);}rep(i,1,m){int lca=Lca(L[i],R[i]);upnode(V[i],1,1,nn,T[L[i]]);upnode(V[i],1,1,nn,T[R[i]]);upnode(V[i],-1,1,nn,T[lca]);if(fa[lca])upnode(V[i],-1,1,nn,T[fa[lca]]);}dfs3(1);rep(i,1,n)printf("%d\n",ans[i]);return 0; }
View Code
也可以用树链剖分差分来做
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) // const int N=1e5+100; int maxx[N<<2],t[N<<2],pos,head[N],ans[N],n,m,a,b,c,pre[N]; vector<int>table[N]; void up(int pos) {if(maxx[pos<<1]>=maxx[pos<<1|1])maxx[pos]=maxx[pos<<1],t[pos]=t[pos<<1];else maxx[pos]=maxx[pos<<1|1],t[pos]=t[pos<<1|1]; } void build(int l,int r,int pos) {if(l==r){maxx[pos]=0;t[pos]=l;return;}int m=(l+r)>>1;build(l,m,pos<<1);build(m+1,r,pos<<1|1);up(pos); } void upnode(int x,int v,int l,int r,int pos) {if(l==r){maxx[pos]+=v;return ;}int m=(l+r)>>1;if(x<=m)upnode(x,v,l,m,pos<<1);else upnode(x,v,m+1,r,pos<<1|1);up(pos); } int son[N],siz[N],fa[N],top[N],id[N],ncnt,dep[N]; struct Edge{int to,nex;}edge[N<<1]; void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;} void dfs1(int x,int f) {fa[x]=f;dep[x]=dep[f]+1;son[x]=0;siz[x]=1;for(int i=head[x];i;i=edge[i].nex){int v=edge[i].to;if(v==f)continue;dfs1(v,x);siz[x]+=siz[v];if(siz[son[x]]<siz[v])son[x]=v;} } void dfs2(int x,int topf) {top[x]=topf;id[x]=++ncnt;pre[ncnt]=x;if(son[x])dfs2(son[x],topf);for(int i=head[x];i;i=edge[i].nex){int v=edge[i].to;if(v==son[x]||v==fa[x])continue;dfs2(v,v);} } void UPsum(int x,int y,int v) {while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);table[id[top[x]]].push_back(v);table[id[x]+1].push_back(-v);x=fa[top[x]];}if(dep[x]>dep[y])swap(x,y);table[id[x]].push_back(v);table[id[y]+1].push_back(-v); } int main() {scanf("%d%d",&n,&m);rep(i,1,n-1){scanf("%d%d",&a,&b);add(a,b);add(b,a);}dfs1(1,1);dfs2(1,1);while(m--){scanf("%d%d%d",&a,&b,&c);UPsum(a,b,c);}build(1,1e5,1);rep(i,1,n){for(auto v:table[i])if(v>0)upnode(v,1,1,1e5,1);else upnode(-v,-1,1,1e5,1);if(maxx[1])ans[pre[i]]=t[1];else ans[pre[i]]=0;}rep(i,1,n)printf("%d\n",ans[i]);return 0; }
View Code
转载于:https://www.cnblogs.com/bxd123/p/11383715.html
P4556 [Vani有约会]雨天的尾巴 树链剖分 线段树合并相关推荐
- 线段树分裂与合并 ---- 树上差分 P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
题目链接 解题思路: 首先题目是对u,vu,vu,v这两条路径上面添加一个zzz,然后运用树上点的差分思想,对于分发路径u,vu,vu,v,我们在uuu上+1+1+1,在vvv上+1+1+1,在lca ...
- 洛谷 - P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并(树上差分+线段树合并)
题目链接:点击查看 题目大意:给出一棵树,再给出 m 次操作,每次操作会选择两个点 ( x , y ) ,使得这条路径上的所有点的种类 z 加一,最后问每个点的哪个种类出现的频率最高,若多个种类出现频 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MB Submit: 1153 Solved: 421 [Submit][Sta ...
- BZOJ3862Little Devil I——树链剖分+线段树
题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...
- CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)
题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...
- CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)
题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...
- P2486 [SDOI2011]染色(树链剖分+线段树)
题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...
- BZOJ4127Abs——树链剖分+线段树
题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
最新文章
- 使用struts2框架来实现CRUD(create、read、update、delete)
- 1024 致敬极客精神,我们有一个3天的秘境邀请!
- ei加声调怎么加_空调怎么加氟 空调加氟方法【介绍】
- mysql 值到99999后不增值了_Mysql 增加新数据,若存在则更新的问题
- matlab中统计数组中各数字(元素)出现的次数
- ZZULIOJ 1097: 计算平均成绩(函数专题)
- [深度学习]为什么梯度反方向是函数值下降最快的方向?
- c++ byte转cbitmap_关于 C++ 打印 PDF 打印及 PDF 转图片、合并
- 《Cracking the Coding Interview》——第3章:栈和队列——题目4
- 【转】用Qt生成dll类库及调用方法
- 计算机网络 课后题答案解析,计算机网络课后习题和答案解析
- html中置顶的命令行是啥,html怎么把置顶
- 快速排序-C语言版(带图详细)
- c语言里的u代表什么_c语言中的 %u 什么意思啊?
- python socks代理_如何让任意python程序使用socks代理
- java中使用poi导出Excel详解,kotlin音标
- Alphat【翻译】
- 打造爆款时怎么做淘宝付费推广?
- 错误:Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/db.properties]
- Win10 home vs pro vs enterprise vs enterprise LTSC
热门文章
- 关于Iphone 4 如何用itunes备份短信等设置
- SINR, RSRP, CQI 关系
- 先分号分隔 然后逗号分割c语言,分隔符的用法
- 2020 春节集五福最详细收集攻略
- [强烈推荐]ring0下文件解锁强制删除工具
- 阿祥Python自学笔记
- word转html java代码_用java实现word转html
- 刚开始参加工作的45条建议
- The remote device or resource won't accept the connect
- 全国IT标准化技术委员会教育技术分会CETSC介绍 (公号回复“CETSC”下载PDF资料,欢迎转发、赞赏支持)