松鼠的新家

链接

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∑n​bi​

因此,如果要使数列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 松鼠的新家相关推荐

  1. [Luogu 3258] JLOI2014 松鼠的新家

    [Luogu 3258] JLOI2014 松鼠的新家 LCA + 树上差分. 我呢,因为是树剖求的 LCA,预处理了 DFN(DFS 序),于是简化成了序列差分. qwq不讲了不讲了,贴代码. #i ...

  2. P3258 [JLOI2014]松鼠的新家(树上点查分)

    题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树"上. ...

  3. P3258 [JLOI2014]松鼠的新家

    文章目录 题意: 题解: 树上差分 代码: 树链剖分 代码: P3258 [JLOI2014]松鼠的新家 题意: n个点,n-1条边,给出每个点的拜访顺序,问每个点经过几次(最后一次移动不算拜访) 题 ...

  4. 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告

    P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...

  5. 3631: [JLOI2014]松鼠的新家

    3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 707  Solved: 342 [Submit][Sta ...

  6. bzoj 3631: [JLOI2014]松鼠的新家(LCA+树上差分)

    3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 2059  Solved: 1030 [Submit][S ...

  7. 刷题总结——松鼠的新家(bzoj3631)

    题目: Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在" ...

  8. 松鼠的新家(树上点差分 + LCA)

    题目: 松鼠的新家是一棵树,前几天刚刚装修好了新家,新家有 个房间,并且有 根树枝连接,每个房间都可以相互到达,且任两个房间之间的路线都是唯一的.天哪,他居然真的住在「树」上.松鼠想邀请小熊维尼前来参 ...

  9. 洛谷 P3258 [JLOI2014]松鼠的新家 树上差分

    缘起 [1]中我们学习了树上差分,并且a了一个裸的点差分. 现在继续树上差分~ 洛谷 P3258 [JLOI2014]松鼠的新家 分析 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房 ...

最新文章

  1. ugui 转轮_Unity3D研究院之Android NDK编译C/C++结合Unity实现本地数据共享(二十八)...
  2. Python收发邮件
  3. 通过ObjectMapper将实体转成字符串 ,将 用json存的的list 回转list
  4. 浅析Codewarrior、IAR和Keil MDK三大开发环境优缺点
  5. 云南省计算机一级理论知识试卷,云南省计算机一级考试模拟试题理论题型
  6. js中“||”和“”的高级用法 js,与或运算符 || 妙用
  7. Java新手造假_老板居然让我在Java项目中“造假”
  8. 容器编排技术 -- Kubernetes kubectl expose命令详解
  9. Exchaneg 2013 集成OWAS
  10. IT程序人生:学会写程序能从事哪些技术岗位?
  11. 【Verilog HDL】38译码器
  12. 3种方法设置PPT文件保护
  13. android studio必须装c盘吗,Android Studio不占用c盘配置
  14. MindManager22全新版思维导图软件工具
  15. 手机WIFI传文件到局域网服务器,iOS 设备实现wifi局域网传输文件到iphone
  16. HTML的img插入本地图片
  17. 微信公众号运营,如何有效的推广
  18. HMM模型 forward backward viterbi算法
  19. Vue3不支持eventBus
  20. 如何转换图片格式?教你三招一键轻松转换图片格式

热门文章

  1. 大厂面试 Mysql数据库相关面试题总结
  2. redhat 中使用更改yumy源为centos的163源
  3. react配置生产环境和测试环境地址
  4. 应用深度学习function-loss-optimization 2020.8.24
  5. 掌上微博android源代码,掌上微博 全能手机
  6. 蜗牛星际风扇噪音的简单解决方案
  7. 【Xpath】使用following-sibling获取后面的同级节点
  8. Linux下文件的读写
  9. 我的世界服务器物品栏太小咋办,《我的世界》MC背包容量太小?这四个装东西的道具了解一下!...
  10. k8s Dashboard 仪表盘