[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大的数是 ...
随机推荐
- Java文件输入输出
public static void FileIO(String filename){ FileInputStream fis = null; try { fis = new FileInputStr ...
- __enter__,__exit__
目录 上下文管理协议 模拟open 优点 我们知道在操作文件对象的时候可以这么写 with open('a.txt') as f: '代码块' 上述叫做上下文管理协议,即with语句,为了让一个对象兼 ...
- [SDOI2019] 热闹又尴尬的聚会
热闹度\(p\)子图中最小的度数,尴尬度\(q\)独立集大小,之间的约束 \[ \begin{aligned} \lfloor n/(p+1)\rfloor\le q &\rightarrow ...
- 快速删除node_modules文件夹
前言 当安装了较多模块后,node_modules目录下的文件会很多,直接删除整个目录会很慢,下面介绍些快速删除node_modules目录的方法. 方法一:使用rimraf模块的命令 在全局安装ri ...
- 洛谷 P4092 [HEOI2016/TJOI2016]树 || bzoj4551
https://www.lydsy.com/JudgeOnline/problem.php?id=4551 https://www.luogu.org/problemnew/show/P4092 这当 ...
- Hive_Hive体系结构
元数据: HQL的执行过程 ORACEL 执行计划,Hive 类似. 无索引时,生成全表扫描执行计划,执行全表扫描. 创建索引后,重新生成SQL语句执行计划,基于索引扫描,提高查询效率.
- 字符串与C51的格式化输出
一字符数组和字符指针: 字符指针可以用字符串对其直接初始化和随时赋值:而字符数组可以用字符串进行初始化,但不能用字符串对其进行随时赋值(但此时可以定义一个字符串指针指向字符数组,然后用字符串对指针随时 ...
- css未知宽度水平居中整理
1.text-align 兼容性很好 .wp {text-align: center;} .test {display: inline;} <ul class="wp"> ...
- SpringBoot项目取消数据库配置
1. 错误springboot项目启动时,如果没有配置数据库配置,启动时会抛出如下异常. Description: Cannot determine embedded database driver ...
- 系统讲解一下,Dao,Entity,Servlet,Action各自有什么东西-Java/Web开发
dao 主要是一些接口,里面定义了一些用于增删改查的方法名 daoImpl 就是对dao的具体实现 Service 同上,也是一些接口,主要是用来调用dao层的一些方法,所以这里定义的方法一般都定义好 ...