[BZOJ3307] 雨天的尾巴-----------------线段树进阶
虽然是个板子,但用到了差分思想。
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] 雨天的尾巴-----------------线段树进阶的更多相关文章
- BZOJ3307雨天的尾巴——线段树合并
题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入 第一行数字N,M接下来N ...
- 【BZOJ3307】雨天的尾巴 线段树合并
[BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...
- [Vani有约会]雨天的尾巴 线段树合并
[Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...
- 洛谷P4556 雨天的尾巴 线段树
正解:线段树合并 解题报告: 传送门! 考虑对树上的每个节点开一棵权值线段树,动态开点,记录一个max(num,id)(这儿的id,define了一下,,,指的是从小到大排QAQ 然后修改操作可以考虑 ...
- bzoj 3307: 雨天的尾巴 线段树合并
题目大意: N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.问完成所有发放后,每个点存放最多的是哪种物品. 题解: 首先我们为每一个节 ...
- P4556 雨天的尾巴 线段树合并
使用线段树合并,每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号(下标).所以每个节点答案即为\(tre[rot[x]]\). 然后运用树上点的差分思想,对于分发路径\(u, ...
- 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)
题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...
- [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)
[BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...
- BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶
是不是每做道线段树进阶都要写个题解..根本不会写 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
随机推荐
- 文件流转换(一般用于axios设置接收文件流设置时responseType: 'blob')
文件流转换 一般用于axios设置接收文件流设置时responseType: 'blob'当接口报错时,前端因已设置responseType: 'blob'无法再接收json格式数据,会把json格式 ...
- confluence 开源破解
一.安装 (一).开源agent https://gitee.com/pengzhile/atlassian-agent (二).dockerfile FROM cptactionhank/atl ...
- 在PHP中操作文件的扩展属性
在操作系统的文件中,还存在着一种我们可以自己定义的文件属性.这些属性不是保存在文件内容中,也不是直接可以通过 ls -al 所能看到的内容.它们可以将一个键值对信息永久得关联到文件上,一般现在的 Li ...
- 使用Jmeter执行接口自动化测试-如何初始化清空旧数据
需求分析: 每次执行完自动化测试,我们不会执行删除接口把数据删除,而需要留着手工测试,此时会导致下次执行测试有旧数据 我们手工可能也会新增数据,导致下次执行自动化测试有旧数据 下面介绍两种清空数据的方 ...
- python二级 之 第 五套
1. 这里要注意输入的 就是列表 . [1,2,3] 2. 就是你要明白 random.seed() 产生随机种子# 与random.randint() 取 ...
- Spring Cloud Gateway 没有链路信息,我 TM 人傻了(下)
本系列是 我TM人傻了 系列第五期[捂脸],往期精彩回顾: 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了 这个大表走索引字段查询的 SQL 怎么就成全扫描了,我TM人傻了 获取异 ...
- Loj#3026-「ROIR 2018 Day1」管道监控【Trie,费用流】
正题 题目链接:https://loj.ac/p/3026 题目大意 给出\(n\)个点的一棵外向树,然后\(m\)个字符串和费用表示你每次可以花费这个费用覆盖路径字符串和给出字符串相等的路径,求覆盖 ...
- P3190-[HNOI2007]神奇游乐园【插头dp】
正题 题目链接:https://www.luogu.com.cn/problem/P3190 题目大意 \(n*m\)的网格上有权值,求一条权值和最大的不交回路. \(1\leq n\leq 100, ...
- P7518-[省选联考2021A/B卷]宝石【主席树,二分】
正题 题目链接:https://www.luogu.com.cn/problem/P7518 题目大意 给出\(n\)个点的一棵树,每个点上有不大于\(m\)的数字. 然后给出一个长度为\(c\)的各 ...
- 在 ASP.NET Core 中自动启用 CAP 事务
本篇文章旨在描述如何在 ASP.NET Core项目中并以一种简便的方式启用CAP事务,因为在我们的示例中都是直接演示比较直观的方式,没有进行封装,有些初学者同学不太会,找到问我如何封装,本篇文章主要 ...