[BZOJ3307]:雨天的尾巴(LCA+树上差分+权值线段树)
题目传送门
题目描述
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。
样例
样例输入:
20 50
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50
(有点长……)
样例输出:
87
36
84
22
87
87
22
50
84
87
50
36
87
93
36
94
16
87
50
50
数据范围与提示
1≤N,M≤100000
1≤a,b,x,y≤N
1≤z≤109
题解
看到这道题我首先想到了这道题:BZOJ3631。
对于上面这道题,如果你还没有思路的话可以看一下这篇博客:[BZOJ3631]:[JLOI2014]松鼠的新家(LCA+树上差分)。
然后,我就立马想到了先求出LCA然后进行树上差分,但是这两道题的区别在于,这道题的物品种类不止一个,而且数还不小,显然不能单纯的用树上差分来解决。
于是考虑用权值线段树维护,先将物品种类排序,然后看利用树上差分更新权值线段树,之后递归合并统计答案即可。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec//存边
{
int nxt;
int to;
}e[200000];
struct qwq//存操作
{
int x;
int y;
int z;
}question[100001];
int head[100001],cnt;
int fa[100001][20];
int root[100001],trfal[10000001],trsum[10000001],ls[10000001],rs[10000001],sum,tot;
int dfsv[100001];
int depth[100001];
int que[100001];
bool cmp(qwq a,qwq b){return a.z<b.z;}//按物品排序问题
void add(int x,int y)//建边
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs(int x)//dfs预处理父亲和深度
{
dfsv[++dfsv[0]]=x;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x][0])
{
fa[e[i].to][0]=x;
depth[e[i].to]=depth[x]+1;
for(int j=1;j<=18;j++)
fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
dfs(e[i].to);
}
}
int LCA(int x,int y)//倍增求LCA
{
if(depth[x]<depth[y])swap(x,y);
for(int i=18;i>=0;i--)
if(depth[fa[x][i]]>=depth[y])x=fa[x][i];
if(x==y)return x;
for(int i=18;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
void pushup(int x)
{
trfal[x]=max(trfal[ls[x]],trfal[rs[x]]);//维护的权值
trsum[x]=(trfal[ls[x]]>=trfal[rs[x]])?trsum[ls[x]]:trsum[rs[x]];//哪种物品
}
void insert(int &x,int k,int fl,int l,int r)
{
if(!x)x=++tot;
if(l==r)
{
trfal[x]+=fl;
trsum[x]=que[l];
return;
}
int mid=(l+r)>>1;
if(k<=mid)insert(ls[x],k,fl,l,mid);
else insert(rs[x],k,fl,mid+1,r);
pushup(x);
}
void ask(int &x,int fl,int l,int r)
{
if(!fl)return;
if(!x)
{
x=fl;
return;
}
if(l==r)
{
trfal[x]+=trfal[fl];
return;
}
int mid=(l+r)>>1;
ask(ls[x],ls[fl],l,mid);
ask(rs[x],rs[fl],mid+1,r);
pushup(x);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)root[i]=i;
tot=n;
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
depth[1]=1;
dfs(1);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&question[i].x,&question[i].y,&question[i].z);
sort(question+1,question+m+1,cmp);
for(int i=1;i<=m;i++)
{
int lca=LCA(question[i].x,question[i].y);
if(question[i].z>question[i-1].z)que[++sum]=question[i].z;
insert(root[question[i].x],sum,1,1,m);//树上差分操作
insert(root[question[i].y],sum,1,1,m);
insert(root[lca],sum,-1,1,m);
if(lca!=1)insert(root[fa[lca][0]],sum,-1,1,m);
}
for(int i=n;i>1;i--)
ask(root[fa[dfsv[i]][0]],root[dfsv[i]],1,m);
for(int i=1;i<=n;i++)
printf("%d\n",trsum[root[i]]);
return 0;
}
rp++
[BZOJ3307]:雨天的尾巴(LCA+树上差分+权值线段树)的更多相关文章
- [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)
[BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...
- 【bzoj3307】雨天的尾巴 权值线段树合并
题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y,对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入 第一行数字N,M接下来 ...
- HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)
layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...
- 【bzoj4719】[Noip2016]天天爱跑步 权值线段树合并
题目描述 给出一棵n个点的树,以及m次操作,每次操作从起点向终点以每秒一条边的速度移动(初始时刻为0),最后对于每个点询问有多少次操作在经过该点的时刻为某值. 输入 第一行有两个整数N和M .其中N代 ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- 线段树(单标记+离散化+扫描线+双标记)+zkw线段树+权值线段树+主席树及一些例题
“队列进出图上的方向 线段树区间修改求出总量 可持久留下的迹象 我们 俯身欣赏” ----<膜你抄> 线段树很早就会写了,但一直没有总结,所以偶尔重写又会懵逼,所以还是要总结一下. ...
- BZOJ_2161_布娃娃_权值线段树
BZOJ_2161_布娃娃_权值线段树 Description 小时候的雨荨非常听话,是父母眼中的好孩子.在学校是老师的左右手,同学的好榜样.后来她成为艾利斯顿第二 代考神,这和小时候培养的良好素质是 ...
- cf1073G Yet Another LCP Problem (SA+权值线段树)
反正先求一遍sa 然后这个问题可以稍微转化一下 默认比较A.B数组中元素的大小都是比较它们rank的大小,毕竟两个位置的LCP就是它们rank的rmq 然后每次只要求B[j]>=A[i]的LCP ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
随机推荐
- IT兄弟连 JavaWeb教程 Servlet会话跟踪 获取Session对象
Session对象的获取有两种: ● 有参方法: HttpSession request.getSession(boolean isNew) 参数: true:获取一个Session对象,如果之前S ...
- iOS7 UITableView Row Height Estimation
This post is part of a daily series of posts introducing the most exciting new parts of iOS7 for dev ...
- RPC跟MQ之间的差异比较
在阿里的平台技术部参与开发了Dubbo(远程调用服务)和Napoli(消息解决方案),又给网站应用支持这2个产品很长一段时间,了解了这2个产品的实现及应用对这两个产品的用法. 大部分情况下,“给定场景 ...
- A - Bi-shoe and Phi-shoe
每一个数字的欧拉函数要大于或等于该数字.求,最小的欧拉函数的下标和的大小. 答案要用longlong存 #include <iostream> #include <algorithm ...
- 个人常用Git操作记录
本地分支与远程分支建立联系 Git - 新建本地分支与远程分支关联问题 查看本地分支与远程分支关系: git branch -vv 当前分支与远程分支建立关系: git branch --set-up ...
- struts2的@Result annotation 如何添加params,并且在页面取值
http://www.bubuko.com/infodetail-2492575.html .............................................. 标签:lai ...
- Springboot下事务管理的简单使用
关于事务管理的概念这里就不多介绍了,在我的博客“JDBC事务之理论篇”中也有介绍. 关于Spring的事务管理,主要是通过事务管理器来进行的.这里看个Spring事务管理的接口图:(来自博客https ...
- 神奇的VIM
1. di'.di".di`.di( .di{ .dt 'abc' ==> '' di' "abc"==> "" di" `ab ...
- GDB 格式化结构体输出
转载:http://blog.csdn.net/unix21/article/details/9991925 set print addressset print address on打开地址输出,当 ...
- python flask学习(2)
本文主要整理下几个Flask扩展: 0.Flask-Bootstrap:集成Twitter开发的一个开源框架Bootstrap.1.Flask-Script:为Flask程序添加一个命令行解析器2.F ...