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

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. MySQL高级语句(一)

    一.MySQL高级进阶SQL 语句 1.SELECT 2.DISTINCT 3.WHERE  4.AND.OR 5.IN 6.BETWEEN 7.通配符.LIKE 8.ORDER BY 9.| | 连 ...

  2. python中时间处理标准库DateTime加强版库:pendulum

    DateTime 的时区问题 Python的datetime可以处理2种类型的时间,分别为offset-naive和offset-aware.前者是指没有包含时区信息的时间,后者是指包含时区信息的时间 ...

  3. 技术栈:springboot2.x,vue,activiti5.22,mysql,带工作流系统

    前言 activiti工作流,企业erp.oa.hr.crm等审批系统轻松落地,请假审批demo从流程绘制到审批结束实例. 一.项目形式 springboot+vue+activiti集成了activ ...

  4. swiper-wrapper轮滑组件(多组轮滑界面)间隔无效问题

    在多组此种轮滑效果出现时,你需要加两个属性值,即 new Swiper('.swiper-container', { slidesPerView: 3, slidesPerColumn: 2, spa ...

  5. win7任务计划提示”该任务映像已损坏或已篡改“

    打开任务计划,弹出了下面的对话框[该任务映像已损坏或已篡改.(异常来自HRESULT:0x80041321)] 首先你以管理员的身份运行cmd命令,打开运行窗口 输入:chcp 437,并回车,回车后 ...

  6. Shell系列(8)- 变量与变量分类(1)

    变量命名规则 开头为字符或下划线,名字中间中能有字母.数字和下划线组成; 变量的长度不超过255个字符; 变量名在有效的范围内必须是唯一的; 如再次定义则会替换上一个变量的值 在Bash中,变量的默认 ...

  7. pycharm 操作excel

    一.安装openpyxl Python中,往excel写入数据通常使用openpyxl库.也可以使用pandas库.这里讲解如何通过openpyxl库操作excel.pip install openp ...

  8. 我在学习Blazor当中踩的巨坑!Blazor WebAssembly调试

    最近嘛,看看Blazor已经蛮成熟的.顺便想在自家的框架里使用这个东西,毕竟我还是很念旧的,而且Blazor的技术栈也不麻烦.然后呢,在调试这一关我可是踩了大坑. 我的VS是2019,很早以前装的.然 ...

  9. 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 百篇博客分析OpenHarmony源码 | v33.02

    百篇博客系列篇.本篇为: v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁 ...

  10. P4831-Scarlet loves WenHuaKe【组合数学】

    正题 题目链接:https://www.luogu.com.cn/problem/P4831 题目大意 \(n*m\)的网格上放置\(2n\)个炮,要求互不能攻击. 数据满足\(n\leq m\leq ...