虽然是个板子,但用到了差分思想。

Description

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。

Solution

离线记录所有操作后把物品编号离散化,

之后修改路径信息时用到了点差分的思想。在线段树中记录差分数据,最后由叶节点开始合并,通过子树求和算出该点实际数据。

每次更改时只在两端点处加1,在lca处减1,再在lca父亲处减1即可。应该很好理解。

另外,应用边差分时,要现将边权化为点权,之后在两端点处加,在lca处减,无需更改lca父亲。(虽然这题没用到

具体看代码实现:

  1 #include<bits/stdc++.h>
2 #define debug cout<<"wrong"<<endl
3 using namespace std;
4 const int NN=1e5+5;
5 int n,m,to[NN<<1],nex[NN<<1],head[NN],num,x[NN],y[NN],z[NN],ans[NN];
6 int dep[NN],f[NN][60],tmp[NN],ext,logg,rt[NN];
7 inline int read(){
8 int x=0,f=1;
9 char ch=getchar();
10 while(ch<'0'||ch>'9'){
11 if(ch=='-') f=-1;
12 ch=getchar();
13 }
14 while(ch>='0'&&ch<='9'){
15 x=(x<<1)+(x<<3)+(ch^48);
16 ch=getchar();
17 }
18 return x*f;
19 }
20 inline void add(int a,int b){
21 to[++num]=b; nex[num]=head[a]; head[a]=num;
22 to[++num]=a; nex[num]=head[b]; head[b]=num;
23 }
24 inline int lca(int a,int b){
25 if(dep[a]>dep[b]) swap(a,b);
26 for(int i=logg;i>=0;i--)
27 if(dep[f[b][i]]>=dep[a]) b=f[b][i];
28 if(a==b) return a;
29 for(int i=logg;i>=0;i--)
30 if(f[a][i]!=f[b][i]) a=f[a][i], b=f[b][i];
31 return f[a][0];
32 }
33 void write(int x){
34 if(x<0) putchar('-'), x=-x;
35 if(x>9) write(x/10);
36 putchar(x%10+'0');
37 }
38 void init(){
39 n=read(); m=read();
40 for(int i=1;i<n;i++) add(read(),read());
41 for(int i=1;i<=m;i++) x[i]=read(), y[i]=read(), tmp[i]=z[i]=read();
42
43 sort(tmp+1,tmp+1+m);
44 ext=unique(tmp+1,tmp+1+m)-tmp-1;
45 for(int i=1;i<=m;i++) z[i]=lower_bound(tmp+1,tmp+ext+1,z[i])-tmp;
46
47 queue<int> q;
48 dep[1]=1; logg=log2(n)+1; q.push(1);
49 while(!q.empty()){
50 int a=q.front(); q.pop();
51 for(int i=head[a];i;i=nex[i]){
52 int b=to[i];
53 if(dep[b]) continue;
54 dep[b]=dep[a]+1; f[b][0]=a;
55 for(int j=1;j<=logg;j++) f[b][j]=f[f[b][j-1]][j-1];
56 q.push(b);
57 }
58 }
59 }
60 struct node{
61 int seg,ls[NN*60],rs[NN*60],typ[NN*60],sum[NN*60];
62 void pushup(int x){
63 if(sum[ls[x]]>=sum[rs[x]]) sum[x]=sum[ls[x]], typ[x]=typ[ls[x]];
64 else sum[x]=sum[rs[x]], typ[x]=typ[rs[x]];
65 }
66 void insert(int &x,int l,int r,int pos,int v){
67 if(!x) x=++seg;
68 if(l==r){
69 typ[x]=pos;
70 sum[x]+=v;
71 return;
72 }
73 int mid=(l+r)>>1;
74 if(pos<=mid) insert(ls[x],l,mid,pos,v);
75 else insert(rs[x],mid+1,r,pos,v);
76 pushup(x);
77 }
78 void marge(int &x,int y,int l,int r){
79 if(!x||!y){ x=x+y; return; }
80 if(l==r){ sum[x]+=sum[y]; typ[x]=l; return; }
81 int mid=(l+r)>>1;
82 marge(ls[x],ls[y],l,mid);
83 marge(rs[x],rs[y],mid+1,r);
84 pushup(x);
85 }
86 }segt;
87 void dfs(int fa,int st){
88 for(int i=head[st];i;i=nex[i]){
89 int t=to[i];
90 if(t==fa) continue;
91 dfs(st,t);
92 segt.marge(rt[st],rt[t],1,ext);
93 }
94 if(segt.sum[rt[st]]) ans[st]=tmp[segt.typ[rt[st]]];
95 }
96 int main(){
97 init();
98 for(int i=1;i<=m;i++){
99 int ca=lca(x[i],y[i]);
100 segt.insert(rt[x[i]],1,ext,z[i],1);
101 segt.insert(rt[y[i]],1,ext,z[i],1);
102 segt.insert(rt[ca],1,ext,z[i],-1);
103 if(f[ca][0]) segt.insert(rt[f[ca][0]],1,ext,z[i],-1);
104 }
105 dfs(0,1);
106 for(int i=1;i<=n;i++)
107 write(ans[i]), putchar('\n');
108 return 0;
109 }

[BZOJ3307] 雨天的尾巴-----------------线段树进阶的更多相关文章

  1. BZOJ3307雨天的尾巴——线段树合并

    题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入 第一行数字N,M接下来N ...

  2. 【BZOJ3307】雨天的尾巴 线段树合并

    [BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...

  3. [Vani有约会]雨天的尾巴 线段树合并

    [Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...

  4. 洛谷P4556 雨天的尾巴 线段树

    正解:线段树合并 解题报告: 传送门! 考虑对树上的每个节点开一棵权值线段树,动态开点,记录一个max(num,id)(这儿的id,define了一下,,,指的是从小到大排QAQ 然后修改操作可以考虑 ...

  5. bzoj 3307: 雨天的尾巴 线段树合并

    题目大意: N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.问完成所有发放后,每个点存放最多的是哪种物品. 题解: 首先我们为每一个节 ...

  6. P4556 雨天的尾巴 线段树合并

    使用线段树合并,每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号(下标).所以每个节点答案即为\(tre[rot[x]]\). 然后运用树上点的差分思想,对于分发路径\(u, ...

  7. 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)

    题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...

  8. [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)

    [BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...

  9. BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶

    是不是每做道线段树进阶都要写个题解..根本不会写 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...

随机推荐

  1. vue.js框架图片上传组件

    html: <div id="app"> <div class="hello"> <div class="upload& ...

  2. 给dubbo贡献源码,做梦都在修bug

    本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star. 一 在之前的文章<redis在微服务领域的贡献>中,从一次面试经历中了解了redi ...

  3. [第十五篇]——Swarm 集群管理之Spring Cloud直播商城 b2b2c电子商务技术总结

    Swarm 集群管理 简介 Docker Swarm 是 Docker 的集群管理工具.它将 Docker 主机池转变为单个虚拟 Docker 主机. Docker Swarm 提供了标准的 Dock ...

  4. freeswitch刷新网关方法

    1.freeswitch xml配置文件新增网关后,使其生效,可以重启freeswitch或者使用命令方式 fs_cli -H 127.0.0.1 -P 8021 -p hmzj -x sofia p ...

  5. Azure 实践(4)- CI/CD .netcore项目Docker构建及部署

    上篇已介绍了.netcore项目构建的相关步骤,本篇继续完善 1.什么是CI/CD CI/CD 中的"CI"始终指持续集成,它属于开发人员的自动化流程.成功的 CI 意味着应用代码 ...

  6. POJ1741——Tree(树的点分治)

    1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-11-17 1 ...

  7. Android仿QQ空间发表动态

    效果展示图: 功能描述:用户点击+会进入发表动态的界面,发表成功后跳转到个人首页. 后续完善:增加个人头像的上传,对界面进行优化,增加点赞和评论的功能. 主要采用listview对内容进行展示,对sq ...

  8. 安卓开发 利用百度识图api进行物体识别(java版)

    之前的随笔中,已经实现了python版本调用api接口,之所以使用python是因为python比java要简洁. 但是我发现在使用过程中,chaquopy插件会弹出底部toast显示"un ...

  9. PHP7兼容mysql_connect的方法

    在php7版本的时候,mysql_connect已经不再被支持了,本文将讲述在代码层面实现php7兼容mysql系列,mysql_connect等操作. PHP7不再兼容mysql系列函数,入mysq ...

  10. ecshop transport.js IE报错(608行),对象不支持此属性或方法 的解决办法

    解决办法: 将if (this.hasOwnProperty(k)) { 改为: if (this.hasOwnProperty && this.hasOwnProperty(k)) ...