1. 程式人生 > >洛谷P3258 [JLOI2014]松鼠的新家

洛谷P3258 [JLOI2014]松鼠的新家

== using () isdigit 題目 val return 裝修 路線

題目描述

松鼠的新家是一棵樹,前幾天剛剛裝修了新家,新家有n個房間,並且有\(n-1\)根樹枝連接,每個房間都可以相互到達,且倆個房間之間的路線都是唯一的。天哪,他居然真的住在”樹“上。

松鼠想邀請小熊維尼前來參觀,並且還指定一份參觀指南,他希望維尼能夠按照他的指南順序,先去\(a_1\),再去\(a_2\),......,最後到\(a_n\),去參觀新家。可是這樣會導致維尼重復走很多房間,懶惰的維尼不停地推辭。可是松鼠告訴他,每走到一個房間,他就可以從房間拿一塊糖果吃。

維尼是個饞家夥,立馬就答應了。現在松鼠希望知道為了保證維尼有糖果吃,他需要在每一個房間各放至少多少個糖果。

因為松鼠參觀指南上的最後一個房間\(a_n\)

是餐廳,餐廳裏他準備了豐盛的大餐,所以當維尼在參觀的最後到達餐廳時就不需要再拿糖果吃了。

輸入輸出格式

輸入格式:

第一行一個整數\(n\),表示房間個數第二行\(n\)個整數,依次描述\(a_1-a_n\)

接下來\(n-1\)行,每行兩個整數\(x\)\(y\),表示標號\(x\)\(y\)的兩個房間之間有樹枝相連。

輸出格式:

一共\(n\)行,第\(i\)行輸出標號為\(i\)的房間至少需要放多少個糖果,才能讓維尼有糖果吃。

輸入輸出樣例

輸入樣例#1:

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

輸出樣例#1:

1
2
1
2
1

說明

\(2 \leq n \leq 300000\)

思路:考慮樹鏈剖分+線段樹,我們自己手玩樣例可以發現,我們按題目中給出的結點訪問順序進行路徑修改,最後把每條路徑的起點的點權\(-1\)(除了起始結點),就是答案了,然後就是一個樹鏈剖分的裸題了。

代碼:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 300007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
int n,m,head[maxn],d[maxn],son[maxn],siz[maxn],id[maxn],w[maxn];
int num,cnt,sum[maxn<<2],top[maxn],fa[maxn],lazy[maxn<<2];
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
struct node {
  int v,nxt;
}e[maxn<<1];
inline void ct(int u, int v) {
  e[++num].v=v;
  e[num].nxt=head[u];
  head[u]=num;
}
inline void pushdown(int rt) {
  if(lazy[rt]) {
    sum[ls]+=lazy[rt],sum[rs]+=lazy[rt];
    lazy[ls]+=lazy[rt],lazy[rs]+=lazy[rt];
    lazy[rt]=0;
  }
}
void modify(int rt, int l, int r, int L, int R, int val) {
  if(L>r||R<l) return;
  if(L<=l&&r<=R) {
    sum[rt]+=val;
    lazy[rt]+=val;
    return;
  }
  pushdown(rt);
  int mid=(l+r)>>1;
  modify(ls,l,mid,L,R,val),modify(rs,mid+1,r,L,R,val);
}
int query(int rt, int l, int r, int L) {
  if(l==r) return sum[rt];
  int mid=(l+r)>>1;
  pushdown(rt);
  if(L<=mid) return query(ls,l,mid,L);
  else return query(rs,mid+1,r,L);
}
void dfs1(int u) {
  siz[u]=1;
  for(int i=head[u];i;i=e[i].nxt) {
    int v=e[i].v;
    if(v!=fa[u]) {
      d[v]=d[u]+1;
      fa[v]=u;
      dfs1(v);
      siz[u]+=siz[v];
      if(siz[v]>siz[son[u]]) son[u]=v;
    }
  }
}
void dfs2(int u, int t) {
  id[u]=++cnt;
  top[u]=t;
  if(son[u]) dfs2(son[u],t);
  for(int i=head[u];i;i=e[i].nxt) {
    int v=e[i].v;
    if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
  }
}
void cal(int x, int y) {
  int fx=top[x],fy=top[y];
  while(fx!=fy) {
    if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
    modify(1,1,cnt,id[fx],id[x],1);
    x=fa[fx],fx=top[x];
  }
  if(id[x]>id[y]) swap(x,y);
  modify(1,1,cnt,id[x],id[y],1);
}
int main() {
  n=qread();
  for(int i=1;i<=n;++i) w[i]=qread();
  for(int i=1,u,v;i<n;++i) {
    u=qread(),v=qread();
    ct(u,v);ct(v,u);
  }
  dfs1(1),dfs2(1,1);
  int now=w[1];
  for(int i=2;i<=n;++i) {
    cal(now,w[i]);
    now=w[i];
    modify(1,1,cnt,id[now],id[now],-1);
  }
  for(int i=1;i<=n;++i) printf("%d\n",query(1,1,cnt,id[i]));
  return 0;
}

洛谷P3258 [JLOI2014]松鼠的新家