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

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. 288 day05_异常,线程

    day05 [异常.线程] 主要内容 异常.线程 教学目标 [ ] 能够辨别程序中异常和错误的区别 [ ] 说出异常的分类 [ ] 说出虚拟机处理异常的方式 [ ] 列举出常见的三个运行期异常 [ ] ...

  2. 大学四年的Python学习笔记分享之一,内容整理的比较多与仔细

    翻到以前在大学坚持记录的Python学习笔记,花了一天的时间整理出来,整理时不经回忆起大学的时光,一眨眼几年就过去了,现在还在上学的你们,一定要珍惜现在,有个充实的校园生活.希望这次的分享对于你们有学 ...

  3. PHP的Mhash扩展函数的学习

    这次我们要学习的又是一个 Hash 加密扩展.不过这个扩展 Mhash 已经集成在了 Hash 扩展中.同时也需要注意的是,这个扩展已经不推荐使用了,我们应该直接使用 Hash 扩展中的函数来进行 H ...

  4. TP5模型开启事务

    和Db开启事务类似,Db是静态方法 $userObj = new UserModel(); $userObj->startTrans(); try { $userObj->data($da ...

  5. 传说中 VUE 的“语法糖”到底是啥?

    一.什么是语法糖? 语法糖也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是计算机语言中添加的一种语法,在不影响功能的情况下,添加某种简单的语 ...

  6. python json格式化打印

    编写python脚本,调试的时候需要打印json格式报文,直接打印看不出层次,可以使用json.dumps格式化打印 import json import requests def test_json ...

  7. 『GoLang』fmt包的使用

    目录 1. fmt 包初识 2. 格式化 verb 应用 2.1 通用 2.2 布尔值 2.3 整数 2.4 浮点数与复数 2.5 字符串和 []byte 2.6 指针 2.7 其他 flag 2.8 ...

  8. linux mint17.3+vmware 12.1.1 流畅安装运行OSX EI capitan

    在linux mint17.3的vmware虚拟机中安装mac osx ei capitan系统 出于对苹果操作系统的好奇与喜爱,分别在宿主机操作系统为windows 7和linux mint17.3 ...

  9. YbtOJ#593-木棍问题【费用流】

    正题 题目链接:https://www.ybtoj.com.cn/contest/114/problem/3 题目大意 \(n*m\)的网格上有一些格子有木球,两个相邻木球直接可以有木棍. 两个\(L ...

  10. 一个故事看懂CPU的TLB

    Hi,我是CPU一号车间的阿Q,还记得我吗,真是好久不见了- 我所在的CPU是一个八核CPU,就有八个工作车间,那运行起来速度杠杆的- 虚拟地址翻译 一大早,我们一号车间MMU(内存管理单元)部门的小 ...