Luogu_P3258 松鼠的新家
松鼠的新家
链接
Luogu_P3258 松鼠的新家
题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有nnn个房间,并且有n−1n-1n−1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。
松鼠想邀请小熊前来参观,并且还指定一份参观指南,他希望小熊能够按照他的指南顺序,先去a1a_1a1,再去 a2a_2a2,……,最后到ana_nan,去参观新家。可是这样会导致重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
小熊是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间 $a_n是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入格式
第一行一个正整数nnn,表示房间个数第二行nnn个正整数,依次描述 a1,a2,⋯,ana_1, a_2,\cdots,a_na1,a2,⋯,an 。
接下来 n−1n-1n−1行,每行两个正整数x,yx,yx,y表示标号xxx和yyy 的两个房间之间有树枝相连。
输出格式
一共nnn行,第iii行输出标号为iii的房间至少需要放多少个糖果,才能让小熊有糖果吃。
输入输出样例
输入 #1
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出 #1
1
2
1
2
1
说明/提示
对于全部的数据,2≤n≤3×105,1≤ai≤n2 \le n \le 3 \times 10^5,1 \le a_i \le n2≤n≤3×105,1≤ai≤n。
思路
这题做的时候,首先看了一下算法标签。差分?是我见识少了!于是赶紧上网查了一下相关知识点。
差分实际上是对数列的一种运算。如数列:
a1,a2,a3,...,ana_1,a_2,a_3,...,a_na1,a2,a3,...,an
那么它的差分数列就应当为:
b1,b2,b3,...,bnb_1,b_2,b_3,...,b_nb1,b2,b3,...,bn
其中,bi=ai−ai−1b_i=a_i-a_{i-1}bi=ai−ai−1。
差分数列有一个性质,那就是:
an=∑i=1nbia_n=\sum_{i=1}^n {b_i}an=i=1∑nbi
因此,如果要使数列aaa在区间[l,r)[l,r)[l,r)中的每一项都+1+1+1,我们就可以将bL+1b_L+1bL+1,同时将bR−1b_R-1bR−1,这样,我们再次求出的数列aaa在区间[l,r)[l,r)[l,r)中的每一项都会在原来的基础上+1+1+1。
当然,光有序列的差分是不够的,因为题目给出的是一棵树啊!
这时候,我们就要用到树上差分了。
在树上差分的算法中,每个节点的原值等于以他为根的子树上所有节点的差分后的值。
如图AAA,这是原树:
如图B,这是经过差分运算后的树:
很显然,如果我们要求某个节点的原值,只需要以它为根,将它所有的子树遍历一遍,把经过的这些节点差分运算后的值加起来,再加上它自己差分运算后的值,就是它的原值。
在树上差分算法中,我们可以对一条链上所有节点的值都进行+1+1+1的运算。如果我们要使连接节点uuu、vvv的路径上所有的点的原值都+1+1+1,只需要将节点uuu、vvv差分运算后的值+1+1+1,将LCA(u,v)LCA(u,v)LCA(u,v)及其父亲差分运算后的值−1-1−1就可以了。
此时,再看看我们的题目,解法就很清晰明了了。
注意,除了第一个经过的节点外,其他经过的节点的原值都要−1-1−1。最后一个节点要−1-1−1是因为“当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了”,其余节点要−1-1−1则是因为每个节点都会做两次的树上差分修改运算,相当于每个节点的原值都+2+2+2而不是+1+1+1。
代码
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=3*100000;
struct str{int to,nex;
}e[2*N+1];
int ls[2*N+1],cnt;
int dep[2*N+1],f[2*N+1][21],ans;
int n,x,y,a[N+1],b[N+1],m,s[N+1],id[N+1];
void add(int u,int v)
{cnt++;e[cnt].to=v;e[cnt].nex=ls[u];ls[u]=cnt;
}
void bfs(int root)
{int fa,so;queue <int> q;dep[root]=1;q.push(root);while(!q.empty()){fa=q.front();q.pop();for(int i=ls[fa];i;i=e[i].nex){so=e[i].to;if(!dep[so]){f[so][0]=fa;//儿子向上跳2^0步就是自己的父亲 dep[so]=dep[fa]+1;q.push(so);}}}
}
void st(int n)
{for(int j=1;j<=20;j++)//预处理f数组:f[i][j]表示从i节点向上跳2^j步到达的节点 for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];//儿子向上跳2^j步就是自己向上跳2^(j-1)步的节点向上跳2^(j-1)步
}
int lca(int x,int y)
{if(dep[x]>dep[y])swap(x,y);int d,k,t;d=dep[y]-dep[x];//深度差 k=20;t=1<<k;while(d)//让较深的跳到与较浅的同一深度 {if(d>=t)//用二进制拆分向上跳 {y=f[y][k];d-=t;};t/=2;k--;}if(x==y)//若x是y的父亲,则lca的值为xreturn x;k=20;while(k>=0)//x与y一起向上跳 {if(f[x][k]!=f[y][k]){x=f[x][k];y=f[y][k];}k--;}return f[x][0];
}
int dfs(int v)
{int sum=0;for(int i=ls[v];i;i=e[i].nex)if(f[v][0]!=e[i].to)//不是它的父亲{s[e[i].to]=dfs(e[i].to);sum+=s[e[i].to];}return sum+b[v];
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);id[a[i]]=i;}for(int i=1;i<=n-1;i++){scanf("%d%d",&x,&y);add(x,y);add(y,x);}bfs(a[1]);st(n);for(int i=1;i<=n-1;i++)//树上差分运算{m=lca(a[i],a[i+1]);b[m]--;b[f[m][0]]--;b[a[i]]++;b[a[i+1]]++;}s[a[1]]=dfs(a[1]);//计算每个节点的原值(真实值)for(int i=1;i<=n;i++)if(i!=1)s[a[i]]--;for(int i=1;i<=n;i++)printf("%d\n",s[i]);return 0;
}
Luogu_P3258 松鼠的新家相关推荐
- [Luogu 3258] JLOI2014 松鼠的新家
[Luogu 3258] JLOI2014 松鼠的新家 LCA + 树上差分. 我呢,因为是树剖求的 LCA,预处理了 DFN(DFS 序),于是简化成了序列差分. qwq不讲了不讲了,贴代码. #i ...
- P3258 [JLOI2014]松鼠的新家(树上点查分)
题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树"上. ...
- P3258 [JLOI2014]松鼠的新家
文章目录 题意: 题解: 树上差分 代码: 树链剖分 代码: P3258 [JLOI2014]松鼠的新家 题意: n个点,n-1条边,给出每个点的拜访顺序,问每个点经过几次(最后一次移动不算拜访) 题 ...
- 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告
P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...
- 3631: [JLOI2014]松鼠的新家
3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 707 Solved: 342 [Submit][Sta ...
- bzoj 3631: [JLOI2014]松鼠的新家(LCA+树上差分)
3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 2059 Solved: 1030 [Submit][S ...
- 刷题总结——松鼠的新家(bzoj3631)
题目: Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在" ...
- 松鼠的新家(树上点差分 + LCA)
题目: 松鼠的新家是一棵树,前几天刚刚装修好了新家,新家有 个房间,并且有 根树枝连接,每个房间都可以相互到达,且任两个房间之间的路线都是唯一的.天哪,他居然真的住在「树」上.松鼠想邀请小熊维尼前来参 ...
- 洛谷 P3258 [JLOI2014]松鼠的新家 树上差分
缘起 [1]中我们学习了树上差分,并且a了一个裸的点差分. 现在继续树上差分~ 洛谷 P3258 [JLOI2014]松鼠的新家 分析 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房 ...
最新文章
- ugui 转轮_Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八)...
- Python收发邮件
- 通过ObjectMapper将实体转成字符串 ,将 用json存的的list 回转list
- 浅析Codewarrior、IAR和Keil MDK三大开发环境优缺点
- 云南省计算机一级理论知识试卷,云南省计算机一级考试模拟试题理论题型
- js中“||”和“”的高级用法 js,与或运算符 || 妙用
- Java新手造假_老板居然让我在Java项目中“造假”
- 容器编排技术 -- Kubernetes kubectl expose命令详解
- Exchaneg 2013 集成OWAS
- IT程序人生:学会写程序能从事哪些技术岗位?
- 【Verilog HDL】38译码器
- 3种方法设置PPT文件保护
- android studio必须装c盘吗,Android Studio不占用c盘配置
- MindManager22全新版思维导图软件工具
- 手机WIFI传文件到局域网服务器,iOS 设备实现wifi局域网传输文件到iphone
- HTML的img插入本地图片
- 微信公众号运营,如何有效的推广
- HMM模型 forward backward viterbi算法
- Vue3不支持eventBus
- 如何转换图片格式?教你三招一键轻松转换图片格式
热门文章
- 大厂面试 Mysql数据库相关面试题总结
- redhat 中使用更改yumy源为centos的163源
- react配置生产环境和测试环境地址
- 应用深度学习function-loss-optimization 2020.8.24
- 掌上微博android源代码,掌上微博 全能手机
- 蜗牛星际风扇噪音的简单解决方案
- 【Xpath】使用following-sibling获取后面的同级节点
- Linux下文件的读写
- 我的世界服务器物品栏太小咋办,《我的世界》MC背包容量太小?这四个装东西的道具了解一下!...
- k8s Dashboard 仪表盘