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

提交2.75k
通过789
时间限制1.00s
内存限制125.00MB

提交代码加入收藏

题目提供者yyy2015c01
难度省选/NOI-
历史分数100

提交记录  查看题解

标签

查看算法标签

相关讨论

进入讨论版

查看讨论

推荐题目

查看推荐

展开

题目背景

深绘里一直很讨厌雨天。
灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。
虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被弄得一片狼藉。
无奈的深绘里和村民们只好等待救济粮来维生。
不过救济粮的发放方式很特别。

题目描述

首先村落里的一共有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复制

5 3
1 2
3 1
3 4
5 3
2 3 3
1 5 2
3 3 3

输出 #1复制

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有约会]雨天的尾巴 树链剖分 线段树合并相关推荐

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

    题目链接 解题思路: 首先题目是对u,vu,vu,v这两条路径上面添加一个zzz,然后运用树上点的差分思想,对于分发路径u,vu,vu,v,我们在uuu上+1+1+1,在vvv上+1+1+1,在lca ...

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

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

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  4. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  5. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  6. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  7. 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 ...

  8. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  9. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  10. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

最新文章

  1. 使用struts2框架来实现CRUD(create、read、update、delete)
  2. 1024 致敬极客精神,我们有一个3天的秘境邀请!
  3. ei加声调怎么加_空调怎么加氟 空调加氟方法【介绍】
  4. mysql 值到99999后不增值了_Mysql 增加新数据,若存在则更新的问题
  5. matlab中统计数组中各数字(元素)出现的次数
  6. ZZULIOJ 1097: 计算平均成绩(函数专题)
  7. [深度学习]为什么梯度反方向是函数值下降最快的方向?
  8. c++ byte转cbitmap_关于 C++ 打印 PDF 打印及 PDF 转图片、合并
  9. 《Cracking the Coding Interview》——第3章:栈和队列——题目4
  10. 【转】用Qt生成dll类库及调用方法
  11. 计算机网络 课后题答案解析,计算机网络课后习题和答案解析
  12. html中置顶的命令行是啥,html怎么把置顶
  13. 快速排序-C语言版(带图详细)
  14. c语言里的u代表什么_c语言中的 %u 什么意思啊?
  15. python socks代理_如何让任意python程序使用socks代理
  16. java中使用poi导出Excel详解,kotlin音标
  17. Alphat【翻译】
  18. 打造爆款时怎么做淘宝付费推广?
  19. 错误:Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/db.properties]
  20. Win10 home vs pro vs enterprise vs enterprise LTSC

热门文章

  1. 关于Iphone 4 如何用itunes备份短信等设置
  2. SINR, RSRP, CQI 关系
  3. 先分号分隔 然后逗号分割c语言,分隔符的用法
  4. 2020 春节集五福最详细收集攻略
  5. [强烈推荐]ring0下文件解锁强制删除工具
  6. 阿祥Python自学笔记
  7. word转html java代码_用java实现word转html
  8. 刚开始参加工作的45条建议
  9. The remote device or resource won't accept the connect
  10. 全国IT标准化技术委员会教育技术分会CETSC介绍 (公号回复“CETSC”下载PDF资料,欢迎转发、赞赏支持)