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\)类型的物品.完成 所有发放后,每个点存放 ...
随机推荐
- T100——英文版凭证报表
范例:cxrr001 效果:增加英文版报表选择 1.azzi301,复制cxrr001_g01,把样板编号改为cxrr001_g01_01: 2.下载cxrr001_g01的GR样板,把cxrr001 ...
- 解决github pages和github .md文件图片不显示
博客园上传的图片,在github上无法显示. 在github项目下建立img文件夹,放上图片 两种方式 项目绝对路径 https://raw.githubusercontent.com/用户名/项目名 ...
- Js 参数乱码
在前台,对URL的中文参数执行两次encodeURI: 序列化 var param = encodeURI(encodeURI("中文")); 反序列化 decodeURI($. ...
- Lab 色彩模型和取值范围
L∈(0,100) a∈(-128,127) b∈(-128,127) opencv 的Lab数据对齐做了量化,使其处于0-255范围 L=L*2.55 a=a+128 b=b+128
- Guava动态调用方法
前言 大家在Coding的时候,经常会遇到这样一个情况,根据不同的条件去执行对应的代码.我们通常的处理方式是利用if-else判断,或者直接switch-case,特别是jdk1.6之后,swith开 ...
- 采购订单保存生成PO号后增强点。
EXIT_SAPMM06E_013 这个增强可用于生成的PO后,调用外部接口把变更或生成的PO信息下发出去. 这里面的参数 I_EKKO 是新的抬头 I_EKKO_OLD 是更改前的抬头 XEKPO ...
- ffmpeg处理视频命令
一:视频添加图片水印 ffmpeg -i a.mp4 -vf "movie=a.jpg[watermark];[in][watermark] overlay=main_w-overlay_w ...
- 在线预览(pptx、ppt、pps、docx、doc、xlsx、xls)
http://view.officeapps.live.com/op/view.aspx?src=<文档位置> 示例文档https://www.dujin.org/file/ppt/duj ...
- Linux基础知识之文件的权限(二)
除了基本的r,w,x之外,在linux传统的ext2.ext3.ext4文件系统下,还可以设置其他 的文件属性.如chattr,lsattr,而在CentOS7中默认利用xfs作为默认的文件系统,就不 ...
- TensorFlow可以在终端和通过终端打开的PyCharm中运行,不能在直接打开的PyCharm中运行
然后看运行窗口的出错信息,点击最右边的view,发现缺少个文件,如代码所示 Traceback (most recent call last): File "/usr/local/lib/p ...