码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj3631】【JLOI2014】松鼠的新家

时间:2018-10-17 19:04:14      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:root   i++   指南   continue   nbsp   typename   span   algorithm   return   

题目描述

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


输入

第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an

接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。


输出

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


样例输入

5
1 4 5 3 2
1 2
2 4
2 3
4 5


样例输出

1
2
1
2
1

 



题解

a[ i ] 到 a[ i+1 ]之间的点+1,a[ i+1 ]再-1,然后查询所有点就ok。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=300000+50;
const int maxm=600000+50;

int n,fa[maxn],m,cnt,a[maxn];
int fir[maxn],nex[maxm],to[maxm],ecnt;
int top[maxn],son[maxn],dep[maxn],sz[maxn],id[maxn];

struct SegmentTree{int v,l,r,add;}st[maxn<<2];

void add(int u,int v){
    nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
}

void dfs1(int x,int f,int deep){
    fa[x]=f;dep[x]=deep;
    sz[x]=1;
    for(int e=fir[x];e;e=nex[e]){
        int v=to[e];
        if(v==f) continue;
        dfs1(v,x,deep+1);
        sz[x]+=sz[v];
        if(sz[v]>sz[son[x]]) son[x]=v;
    }
}

void dfs2(int x,int topf){
    top[x]=topf;
    id[x]=++cnt;
    if(!son[x]) return ;
    dfs2(son[x],topf);
    for(int e=fir[x];e;e=nex[e]){
        int v=to[e];
        if(v==fa[x]||v==son[x]) continue;
        dfs2(v,v);
    }
}

void pushup(int root){
    st[root].v=st[root<<1].v+st[root<<1|1].v;
}

void build(int root,int l,int r){
    st[root].l=l;st[root].r=r;
    if(l==r) return ;
    int m=l+r>>1;
    build(root<<1,l,m);build(root<<1|1,m+1,r);
    pushup(root);
}

void pushdown(int root){
    st[root<<1].v=st[root<<1].v+st[root].add*(st[root<<1].r-st[root<<1].l+1);
    st[root<<1|1].v=st[root<<1|1].v+st[root].add*(st[root<<1|1].r-st[root<<1|1].l+1);
    st[root<<1].add=st[root<<1].add+st[root].add;
    st[root<<1|1].add=st[root<<1|1].add+st[root].add;
    st[root].add=0;
}

void add(int root,int l,int r,int val){
    if(st[root].l>r||st[root].r<l) return ;
    if(st[root].l>=l&&st[root].r<=r){
        st[root].v=st[root].v+val*(st[root].r-st[root].l+1);
        st[root].add=st[root].add+val;
    }
    else{
        pushdown(root);
        add(root<<1,l,r,val);add(root<<1|1,l,r,val);
        pushup(root);
    }
}

int query(int root,int l,int r){
    if(st[root].l>r||st[root].r<l) return 0;
    if(st[root].l>=l&&st[root].r<=r) return st[root].v;
    pushdown(root);
    return query(root<<1,l,r)+query(root<<1|1,l,r);
}

void change(int x,int y,int val){
    int f1=top[x],f2=top[y];
    while(f1!=f2){
        if(dep[f1]<dep[f2]) swap(x,y),swap(f1,f2);
        add(1,id[f1],id[x],val);
        x=fa[f1],f1=top[x];
    }
    if(dep[x]>dep[y]) swap(x,y);
    add(1,id[x],id[y],val);
}

template<typename T>void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<0||cc>9)&&cc!=-) cc=getchar();
    if(cc==-) ff=-1,cc=getchar();
    while(cc>=0&&cc<=9) aa=aa*10+cc-0,cc=getchar();
    aa*=ff;
}

int main(){
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<n;i++){
        int x,y;
        read(x),read(y);
        add(x,y);add(y,x);
    }
    dfs1(1,0,1);dfs2(1,1);build(1,1,n);
    for(int i=1;i<n;i++){
        change(a[i],a[i+1],1);
        change(a[i+1],a[i+1],-1);
    }
    for(int i=1;i<=n;i++) printf("%d\n",query(1,id[i],id[i]));
    return 0;
}

 

【bzoj3631】【JLOI2014】松鼠的新家

标签:root   i++   指南   continue   nbsp   typename   span   algorithm   return   

原文地址:https://www.cnblogs.com/rlddd/p/9806235.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!