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
----------------------------------van美分界线----------------------------------
先%一发pa大佬考试A掉这题
%%%pa
考试时刚看到这题时觉得和之前的考试题松鼠的新家(此坑未填)很像,因为都是对树上的一条链进行修改操作
所以很容易想到树上差分(其实树剖也可以但蒟蒻博主并不会),具体讲就是将链的两端加一,将lca和lca父亲节点减一。
然后我们可以看到他是询问数量所以可以想到在每一个节点建一棵权值线段树来维护信息。
又看到1e9的范围瞬间吓尿,跑去码T1,其实只要离散化一下就可以,因此我们不仅需要维护每一个节点的最大值,还要维护最大值出现的位置,这样比较方便输出答案,建立对应关系即可。
最后dfs统计答案即可,就是从叶节点往上不断merge。
最后要注意的一点就是和线段树有关的数组一定要开大一些,本人亲测要1e5×60,临接表数组开二倍(都这时候了我还犯这么低级错误,真沙雕)。
回想一下这题也没那么难,但我还是断断续续调了得有5.6节课,沙雕错误百出。具体沙雕错误代码里都有注释(大佬自动忽略即可,勿喷)。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+;
int n,m;int tot;int t;
int first[N],nex[N*],to[N*],cnt,d[N],root[N**],v[N],f[N][],sum[N**],posm[N**],ls[N**],rs[N**],ans[N],x[N],yy[N],zz[N],num[N];
void add(int a,int b){
to[++tot]=b;nex[tot]=first[a];first[a]=tot;
}
void bfs(int x){
queue<int> q;
q.push(x);d[x]=;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=first[x];i;i=nex[i]){
int y=to[i];
if(d[y]) continue;
d[y]=d[x]+;
f[y][]=x;
for(int j=;j<=t;j++)
f[y][j]=f[f[y][j-]][j-];
q.push(y);
}
}
}
int Lca(int x,int y){
if(d[y]<d[x]) swap(x,y);
for(int i=t;i>=;i--){
if(d[f[y][i]]>=d[x]) y=f[y][i];
}
if(x==y) return x;
for(int i=t;i>=;i--){
if(f[y][i]!=f[x][i]) x=f[x][i],y=f[y][i];
}
return f[x][];
}
void pushup(int x){
if(sum[ls[x]]>=sum[rs[x]]) sum[x]=sum[ls[x]],posm[x]=posm[ls[x]];
else sum[x]=sum[rs[x]],posm[x]=posm[rs[x]];
}
void update(int &x,int z,int add,int l,int r){
if(!x){
x=++cnt;
}
if(l==r){
sum[x]+=add;posm[x]=z/*z !l*/;
return;//void return sbsbsbsb
}
int mid=(l+r)>>;
if(z<=mid){
update(ls[x],z,add,l,mid);//
}
else update(rs[x],z,add,mid+,r);//递归儿子啊喂
pushup(x);
}
int merge(int x,int y,int l,int r){
if(!x||!y){
return x+y;
}
if(l==r){
sum[x]+=sum[y];
return x;
}
int mid=(l+r)>>;
ls[x]=merge(ls[x],ls[y],l,mid);
rs[x]=merge(rs[x],rs[y],mid+,r);
pushup(x);
return x;
}
void dfs(int x){
for(int i=first[x];i;i=nex[i]){
int y=to[i];
if(y==f[x][]) continue;
//root[x]=merge(root[x],root[y],ls[x],rs[x]); my wrong way
dfs(y);
root[x]=merge(root[x],root[y],,m);
}
if(sum[root[x]])ans[x]=num[posm[root[x]]];//num[posm[root[x]]] x wai yaojia root
}
int main(){
scanf("%d%d",&n,&m);
t=log2(n);
for(int i=;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
bfs();
for(int i=;i<=m;i++){
scanf("%d%d%d",&x[i],&yy[i],&zz[i]);
num[i]=zz[i];
}
sort(num+,num++m);
for(int i=;i<=m;i++){
zz[i]=lower_bound(num+,num+m/*m !n*/+,zz[i])-num;
int lca=Lca(x[i],yy[i]);
update(root[x[i]],zz[i],,,m);update(root[yy[i]],zz[i],,,m);update(root[lca],zz[i],-,,m);if(f[lca][])update(root[f[lca][]],zz[i],-,,m);
}
dfs();
for(int i=;i<=n;i++) printf("%d\n",ans[i]);
}
我还是太弱了,orzorz。
bzoj3307 雨天的尾巴题解及改题过程(线段树合并+lca+树上差分)的更多相关文章
- P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...
- bzoj3307 雨天的尾巴 题解(线段树合并+树上差分)
Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后,每个点存放最多的是哪种物品. Input ...
- P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)
P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...
- bzoj 3307: 雨天的尾巴【树剖lca+树上差分+线段树合并】
这居然是我第一次写线段树合并--所以我居然在合并的时候加点结果WAWAWAMLEMLEMLE--!ro的时候居然直接指到la就行-- 树上差分,每个点建一棵动态开点线段树,然后统计答案的时候合并即可 ...
- 【HNOI2012】永无乡 题解(并查集+线段树合并)
题目链接 给定一张含$n$个点$m$条边的无向图,每个点有一个重要指数$a_i$.有两种操作:1.在$x$和$y$之间连一条边:2.求$x$所在连通块中重要程度第$k$小的点. ----------- ...
- 【BZOJ3307】雨天的尾巴 题解(树链剖分+树上差分)
题目链接 题目大意:给定一颗含有$n$个结点的树,每次选择两个结点$x$和$y$,对从$x$到$y$的路径上发放一带$z$类型的物品.问完成所有操作后每个结点发放最多的时哪种物品. 普通的树链剖分貌似 ...
- 【BZOJ3307】雨天的尾巴 线段树合并
[BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...
- [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)
[BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...
- 雨天的尾巴(bzoj3307)(线段树合并+树上差分)
\(N\)个点,形成一个树状结构.有\(M\)次发放,每次选择两个点\(x,y\) 对于\(x\)到\(y\)的路径上(含\(x,y\))每个点发一袋\(Z\)类型的物品.完成 所有发放后,每个点存放 ...
随机推荐
- Python解释器换源
Python解释器换源 """ 1.采用国内源,加速下载模块的速度 2.常用pip源: -- 豆瓣:https://pypi.douban.com/simple -- 阿 ...
- 简易计算器-leetcode
今天,开始在leetcode上面开始做题,第一个题目是: Implement a basic calculator to evaluate a simple expression string. Th ...
- 【动态规划】Mathematical Curse
[来源]:2018年焦作网络赛B [题意]: 有n个数字,有m个符号运算.通过不回头(即选取m个数有顺序可言),消除巫术的,并达到最大的价值. 其实意思就是在数组里选取一段子序列,然后进行m次加减乘除 ...
- mpstat
mpstat--multiprocessor statistics,统计多处理器的信息 1.安装mpstat工具 [root@localhost ~]# yum install sysstat 2:展 ...
- NYOJ 石子合并(一) 区间dp入门级别
描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求出总的代价 ...
- 装了vs2010 SP1后,开机速度慢
只要到服务里把 Microsoft .NET Framework NGEN v4.0.30319_X86 这个改成手动停止 或 禁用就可以 对vs没有影响 PS:禁了这个服务,开发wcf 在调试的 ...
- kali入侵服务器的那一套实战
dnsenum -enum xxxxx.com 枚举出网站的所有域名和服务器的ip地址 打开百度查询ip地址的所在地 whatweb xxxx.com 查看那些网站入口可以访问 以状 ...
- maven中如何将所有引用的jar包打包到一个jar中
在pom文件的build节点中添加这个插件的引用: <plugins> <plugin> <artifactId>maven-assembly-plugin< ...
- 阿里云环境中配置tomcat7可能出现的问题及解决方法
前提是安装好了tomcat,但是输入ip+端口无法访问,那么情况有一下几种 (1)可能防火墙没有关闭 systemctl stop firewalld.service #停止firewall syst ...
- Intellij IDEA显示调用时序图插件SequenceDiagram
1 推荐一个插件SequenceDiagram可以自动生成项目调用的时序图 安装好之后重启idea即可 2 使用,找到你要查询的方法