[BZOJ3631][JLOI2014]松鼠的新家

Time Limit: 10 Sec
Memory Limit: 128 MB

Description
松鼠的新家是一棵樹,前幾天剛剛裝修了新家,新家有nn個房間,並且有n1n-1根樹枝連接,每個房間都可以相互到達,且倆個房間之間的路線都是唯一的。天哪,他居然真的住在“樹”上。松鼠想邀請小熊維尼前來參觀,並且還指定一份參觀指南,他希望維尼能夠按照他的指南順序,先去a1a_1,再去a2a_2,……,最後到ana_n,去參觀新家。
可是這樣會導致維尼重複走很多房間,懶惰的維尼不聽地推辭。可是松鼠告訴他,每走到一個房間,他就可以從房間拿一塊糖果吃。維尼是個饞傢伙,立馬就答應了。
現在松鼠希望知道爲了保證維尼有糖果吃,他需要在每一個房間各放至少多少個糖果。因爲松鼠參觀指南上的最後一個房間ana_n是餐廳,餐廳裏他準備了豐盛的大餐,所以當維尼在參觀的最後到達餐廳時就不需要再拿糖果吃了。
Input
第一行一個整數nn,表示房間個數
第二行nn個整數,依次描述a1ana_1-a_n
接下來n1n-1行,每行兩個整數xyx,y,表示標號xxyy的兩個房間之間有樹枝相連。
Output
一共nn行,第ii行輸出標號爲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<=3000002<= n <=300000

題解:
樹鏈剖分+線段樹區間修改,nlog22(n)nlog^2_{2}(n)強行過了30萬…
每條路徑直接覆蓋,然後非起始點的點的答案需要1-1,因爲會被加兩次。

upd:聽說有樹上差分這種操作…明天再學吧。

#include<bits/stdc++.h>
#define LiangJiaJun main
#define INF 1999122700
using namespace std;
struct edge{
    int to,nt;
}e[600004];
struct tree{
    int tag,l,r,w;
}tr[1200004];
int n,ne,h[300004];
int cnt,a[300004];
int belong[300004],fa[300004],sz[300004],pos[300004],dep[300004];
void add(int u,int v){
     e[++ne].to=v;e[ne].nt=h[u];
     h[u]=ne;
}
void push(int k){
     if(tr[k].tag==0)return ;
     int g=tr[k].tag;tr[k].tag=0;
     tr[k<<1].tag+=g;
     tr[k<<1|1].tag+=g;
     tr[k<<1].w+=g;
     tr[k<<1|1].w+=g;
     return ;
}
void build(int k,int l,int r){
     tr[k].l=l;tr[k].r=r;
     tr[k].tag=0;tr[k].w=0;
     if(l==r)return ;
     int mid=(l+r)>>1;
     build(k<<1,l,mid);
     build(k<<1|1,mid+1,r);
}
void inc(int k,int a,int b,int v){
     int l=tr[k].l,r=tr[k].r;
     if(l==a&&r==b){
        tr[k].tag+=v;
        tr[k].w+=v;
        return ;
     }
     push(k);
     int mid=(l+r)>>1;
     if(b<=mid)inc(k<<1,a,b,v);
     else if(a>mid)inc(k<<1|1,a,b,v);
     else{
        inc(k<<1,a,mid,v);
        inc(k<<1|1,mid+1,b,v);
     }
}
int ask(int k,int x){
    int l=tr[k].l,r=tr[k].r;
    if(l==x&&r==x)return tr[k].w;
    push(k);
    int mid=(l+r)>>1;
    if(x<=mid)return ask(k<<1,x);
    else return ask(k<<1|1,x);
}

void CLEAR(){
     ne=0;cnt=0;sz[0]=0;
     memset(h,0,sizeof(h));
}
void dfs1(int x){
     sz[x]=1;
     for(int i=h[x];i;i=e[i].nt){
         if(e[i].to==fa[x])continue;
         fa[e[i].to]=x;
         dep[e[i].to]=dep[x]+1;
         dfs1(e[i].to);
         sz[x]+=sz[e[i].to];
     }
     return ;
}
void dfs2(int x,int chain){
     int deg=0;
     pos[x]=++cnt;
     belong[x]=chain;
     for(int i=h[x];i;i=e[i].nt){
         if(e[i].to==fa[x])continue;
         if(sz[deg]<sz[e[i].to]){
            deg=e[i].to;
         }
     }
     if(!deg)return ;
     dfs2(deg,chain);
     for(int i=h[x];i;i=e[i].nt){
         if(e[i].to==fa[x])continue;
         if(e[i].to!=deg)dfs2(e[i].to,e[i].to);
     }
     return ;
}
void solve(int x,int y){
     while(belong[x]!=belong[y]){
        if(dep[belong[x]]<dep[belong[y]])swap(x,y);
        inc(1,pos[belong[x]],pos[x],1);
        x=fa[belong[x]];
     }
     if(pos[x]>pos[y])swap(x,y);
     inc(1,pos[x],pos[y],1);
     return ;
}
int w33ha(){
    CLEAR();
    build(1,1,n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dep[0]=1;
    dfs1(1);
    dfs2(1,1);
    for(int i=1;i<n;i++)solve(a[i],a[i+1]);
    for(int i=1;i<=n;i++)printf("%d\n",ask(1,pos[i])-(a[1]!=i));
    return 0;
}
int LiangJiaJun(){
    while(scanf("%d",&n)!=EOF)w33ha();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章