[Bzoj3631][JLOI2014]松鼠的新家 (树上前缀和)
2017-11-04 15:22
453 查看
3631: [JLOI2014]松鼠的新家
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2350 Solved: 1212
[Submit][Status][Discuss]
Description
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。 可是这样会导致维尼重复走很多房间,懒惰的维尼不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。维尼是个馋家伙,立马就答应了。 现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
Input
第一行一个整数n,表示房间个数 第二行n个整数,依次描述a1-an 接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
Output
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。
Sample Input
5 1 4 5 3 2 1 2 2 4 2 3 4 5
Sample Output
1 2 1 2 1
HINT
2<= n <=300000
分析:
今天做了noip2015 day2 t3,发现这道省选题竟然是它的简化版。。。。。。。。
道理一样求树上前缀和,以第一个访问的为根,求出dfs序(每个点的st和en)和lca。
对于每一个访问的点u,和前一个点pre在前缀和数组里 +1,他们的lca -2.
这样对于除了根节点以外的所有点,他们的起始位置到结尾位置的和就为那条边经过的次数。(这个用前缀和O(n)处理,每次求一个点只用sum[en] - sum[st - 1]就可以了)。
对于每条边出现次数x,两端的点答案各加x/2,如果为奇数深度更深的那个点答案再加1
根节点最后要加一,最后位置要减1,其实比noip那道题还简单。。。。。
AC代码:
# include <iostream> # include <cstdio> # include <cstring> # include <cstdlib> # include <algorithm> using namespace std; const int N = 3e5 + 12; int head ,cnt,n,lg,maxn; int fa [31],dep ,vis ; struct Edge{ int to,next; }edge[N << 1]; void AddEdge(int u,int v){ Edge E = {v,head[u]}; edge[++cnt] = E;head[u] = cnt; } int st ,en ; long long ans ,sum ; void dfs(int u,int pre){ st[u] = ++cnt; for(int i = head[u];i;i = edge[i].next){ int v = edge[i].to; if(v == pre)continue; fa[v][0] = u; dep[v] = dep[u] + 1; dfs(v,u); } maxn = max(maxn,dep[u]); en[u] = cnt; } int lca(int x,int y){ if(dep[x] < dep[y])swap(x,y); for(int i = lg;i >= 0;i--){ if(dep[x] - (1 << i) >= dep[y])x = fa[x][i]; } for(int i = lg;i >= 0;i--){ if((dep[x] - (1 << i)) && fa[x][i] != fa[y][i]){ x = fa[x][i]; y = fa[y][i]; } } if(x != y)x = fa[x][0]; return x; } int main(){ scanf("%d",&n); int x,y,root; for(int i = 1;i <= n;i++){ scanf("%d",&vis[i]); } root = vis[1]; for(int i = 1;i < n;i++){ scanf("%d %d",&x,&y); AddEdge(x,y); AddEdge(y,x); } cnt = 0; dep[root] = maxn = 1; dfs(root,-1); int pre = root; for(lg = 0;(1 << lg) <= maxn;lg++);lg--; for(int j = 1;j <= lg;j++){ for(int i = 1;i <= n;i++){ fa[i][j] = fa[fa[i][j - 1]][j - 1]; } } for(int i = 1;i <= n;i++){ sum[st[vis[i]]]++;sum[st[pre]]++; sum[st[lca(vis[i],pre)]] -= 2; pre = vis[i]; } for(int i = 1;i <= n;i++){ sum[i] += sum[i - 1]; } long long z; for(int i = 1;i <= n;i++){ z = sum[en[i]] - sum[st[i] - 1]; if(z & 1LL){ ans[i]++; } ans[i] += z / 2LL;ans[fa[i][0]] += z / 2LL; } ans[pre]--;ans[root]++; for(int i = 1;i <= n;i++){ printf("%lld\n",ans[i]); } }
相关文章推荐
- BZOJ 3631 [JLOI2014]松鼠的新家 | 树上差分
- bzoj 3631: [JLOI2014]松鼠的新家(LCA+树上差分)
- [bzoj3631][JLOI2014]松鼠的新家 树上差分
- BZOJ 3631: [JLOI2014]松鼠的新家 树上差分
- bzoj3631: [JLOI2014]松鼠的新家 (树上差分)
- [JLOI2014][BZOJ3631] 松鼠的新家|树上倍增LCA|差分
- 【BZOJ】3631 [JLOI2014]松鼠的新家 LCA+树上差分
- BZOJ3631 [JLOI2014]松鼠的新家 【树上差分】
- [BZOJ3631]JLOI2014松鼠的新家|树上差分
- BZOJ3631 [JLOI2014]松鼠的新家 【树上差分】
- bzoj 3631: [JLOI2014]松鼠的新家
- BZOJ3631 [JLOI2014]松鼠的新家
- 【BZOJ3631】[JLOI2014]松鼠的新家 树链剖分
- bzoj 3631: [JLOI2014]松鼠的新家 树链剖分
- 【树链剖分】【JLOI 2014】【bzoj 3631】松鼠的新家
- 【树链剖分】【树状数组】【最近公共祖先】【块状树】bzoj3631 [JLOI2014]松鼠的新家
- [BZOJ3631][JLOI2014]松鼠的新家(链剖)
- BZOJ3631 [JLOI2014] 松鼠的新家
- 【bzoj 3631】[JLOI2014]松鼠的新家(树链剖分)
- BZOJ3631: [JLOI2014]松鼠的新家