您的位置:首页 > 其它

BZOJ3631 [JLOI2014] 松鼠的新家

2015-12-20 16:06 295 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3631

Description

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。
可是这样会导致维尼重复走很多房间,懒惰的维尼不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。维尼是个馋家伙,立马就答应了。
现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

Input

第一行一个整数n,表示房间个数
第二行n个整数,依次描述a1-an
接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

Output

一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。

以前第一次看到认为是倍增,现在一眼扫过去裸链剖……我还是Too young, too simple, sometimes naive.

这道题要求对每一个节点都输出答案,实测对整棵树自上而下递归一次记录每个节点的答案,比用普通线段树通用的询问方法能快300ms左右。

对于某个节点,如果它不是起点则要将答案减1(因为有重复计算)。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define rep(i,l,r) for(int i=l; i<=r; i++)
#define clr(x,y) memset(x,y,sizeof(x))
#define travel(x) for(Edge *p=last[x]; p; p=p->pre)
using namespace std;
const int maxn = 300010;
struct Edge{
Edge *pre;
int to;
}edge[maxn<<1];
Edge *last[maxn],*pt;
struct node{
int l,r,v,t;
}t[maxn<<2];
int n,x,y,segnum=0,a[maxn],depth[maxn],fa[maxn],size[maxn],pos[maxn],belong[maxn],ans[maxn];
bool vis[maxn];
inline int read(){
int ans = 0, f = 1;
char c = getchar();
while (!isdigit(c)){
if (c == '-') f = -1;
c = getchar();
}
while (isdigit(c)){
ans = ans * 10 + c - '0';
c = getchar();
}
return ans * f;
}
inline void addedge(int x,int y){
pt->pre = last[x]; pt->to = y; last[x] = pt++;
}
void dfs1(int x){
vis[x] = 1; size[x] = 1;
travel(x){
if (vis[p->to]) continue;
depth[p->to] = depth[x] + 1;
fa[p->to] = x;
dfs1(p->to);
size[x] += size[p->to];
}
}
void dfs2(int x,int chain){
int k = 0; pos[x] = ++segnum; belong[x] = chain;
travel(x){
if (depth[p->to] == depth[x] + 1 && size[p->to] > size[k])
k = p->to;
}
if (!k) return;
dfs2(k,chain);
travel(x){
if (p->to != k && depth[p->to] > depth[x])
dfs2(p->to,p->to);
}
}
inline void pushdown(int w){
if ((!t[w].t) || t[w].l == t[w].r) return;
t[w<<1].t += t[w].t; t[w<<1|1].t += t[w].t;
t[w<<1].v += (t[w<<1].r - t[w<<1].l + 1) * t[w].t;
t[w<<1|1].v += (t[w<<1|1].r - t[w<<1|1].l + 1) * t[w].t;
t[w].t = 0;
}
inline void maintain(int w){
t[w].v = t[w<<1].v + t[w<<1|1].v;
}
void build(int u,int v,int w){
t[w].l = u; t[w].r = v; t[w].v = t[w].t = 0;
if (u == v) return;
int mid = (u + v) >> 1;
build(u,mid,w<<1); build(mid+1,v,w<<1|1);
}
void change(int u,int v,int w){
pushdown(w);
if (u == t[w].l && v == t[w].r){
t[w].v += v - u + 1;
t[w].t += 1;
return;
}
int mid = (t[w].l + t[w].r) >> 1;
if (v <= mid) change(u,v,w<<1);
else if (u > mid) change(u,v,w<<1|1);
else{
change(u,mid,w<<1);
change(mid+1,v,w<<1|1);
}
maintain(w);
}
void getans(int u,int v,int w){
pushdown(w);
if (u == v){
ans[u] = t[w].v;
return;
}
int mid = (u + v) >> 1;
getans(u,mid,w<<1); getans(mid+1,v,w<<1|1);
}
void modify(int x,int y){
while (belong[x] != belong[y]){
if (depth[belong[x]] < depth[belong[y]]) swap(x,y);
change(pos[belong[x]],pos[x],1);
x = fa[belong[x]];
}
if (depth[x] < depth[y]) swap(x,y);
change(pos[y],pos[x],1);
}
int main(){
n = read(); rep(i,1,n) a[i] = read();
clr(last,0); pt = edge;
rep(i,1,n-1){
x = read(); y = read(); addedge(x,y); addedge(y,x);
}
clr(vis,0); depth[1] = 1; dfs1(1); dfs2(1,1);
build(1,n,1);
rep(i,2,n) modify(a[i],a[i-1]);
getans(1,n,1);
rep(i,1,n){
printf("%d\n",i == a[1] ? ans[pos[i]] : ans[pos[i]] - 1);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: