【JLOI 2014】松鼠的新家
【題目】
題目描述:
松鼠的新家是一棵樹,前幾天剛剛裝修了新家,新家有 個房間,並且有 根樹枝連線,每個房間都可以相互到達,且任意兩個房間之間的路線都是唯一的。天哪,他居然真的住在「樹」上。
松鼠想邀請小熊維尼前來參觀,並且還指定一份參觀指南,他希望維尼能夠按照他的指南順序,先去 ,再去 ,…,最後到 ,去參觀新家。
可是這樣會導致維尼重複走很多房間,懶惰的維尼不停地推辭。可是松鼠告訴他,每走到一個房間,他就可以從房間拿一塊糖果吃。維尼是個饞傢伙,立馬就答應了。現在松鼠希望知道為了保證維尼有糖果吃,他需要在每一個房間各放至少多少個糖果。
因為松鼠參觀指南上的最後一個房間 是餐廳,餐廳裡他準備了豐盛的大餐,所以當維尼在參觀的最後到達餐廳時就不需要再拿糖果吃了。
輸入格式:
第一行,一個整數 ,表示房間個數。
第二行, 個整數,依次描述 ∼ 。 接下來 行,每行兩個整數 , ,表示標號 和 的兩個房間之間有樹枝相連。
輸出格式:
一共 行,第 行輸出標號為 的房間至少需要放多少個糖果,才能讓維尼有糖果吃。
樣例資料:
輸入
5
1 4 5 3 2
1 2
2 4
2 3
4 5
輸出
1
2
1
2
1
備註:
【資料範圍與提示】
對於所有資料,
≤
≤
【分析】
題解:樹鏈剖分+線段樹
我們根據題目中給出的房間 的順序,每次從 走到 時,就把 到 路徑上的糖果加 ( 這個點不加)
還有一些細節操作就是按照上面的操作下來 少算了一次, 多算了一次,要特殊處理一下
然後其餘的就相當於是樹鏈剖分模板了
【程式碼】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300005
#define M 600005
using namespace std;
int n,m,t,tot;
int first[N],v[M],next[M],add[N<<2],sum[N<<2];
int a[N],dep[N],son[N],size[N],top[N],pos[N],father[N];
void edge(int x,int y)
{
t++;
next[t]=first[x];
first[x]=t;
v[t]=y;
}
void point(int x,int y)
{
top[x]=y;
pos[x]=++tot;
}
void dfs1(int x)
{
int i,j;
size[x]=1;
for(i=first[x];i;i=next[i])
{
j=v[i];
if(j!=father[x])
{
father[j]=x;
dep[j]=dep[x]+1;
dfs1(j);
size[x]+=size[j];
if(size[son[x]]<size[j])
son[x]=j;
}
}
}
void dfs2(int x)
{
int i,j;
if(son[x])
{
point(son[x],top[x]);
dfs2(son[x]);
}
for(i=first[x];i;i=next[i])
{
j=v[i];
if(j!=son[x]&&j!=father[x])
{
point(j,j);
dfs2(j);
}
}
}
void pushdown(int root,int l,int r,int mid)
{
add[root<<1]+=add[root];
add[root<<1|1]+=add[root];
sum[root<<1]+=add[root]*(mid-l+1);
sum[root<<1|1]+=add[root]*(r-mid);
add[root]=0;
}
void modify(int root,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
{
add[root]+=k;
sum[root]+=k*(r-l+1);
return;
}
int mid=(l+r)>>1;
if(add[root]) pushdown(root,l,r,mid);
if(x<=mid) modify(root<<1,l,mid,x,y,k);
if(y>mid) modify(root<<1|1,mid+1,r,x,y,k);
sum[root]=sum[root<<1]+sum[root<<1|1];
}
void revise(int x,int y)
{
modify(1,1,n,pos[x],pos[x],-1);
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
modify(1,1,n,pos[top[x]],pos[x],1);
x=father[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
modify(1,1,n,pos[x],pos[y],1);
}
int find(int root,int l,int r,int x)
{
if(l==r)
return sum[root];
int mid=(l+r)>>1;
if(add[root]) pushdown(root,l,r,mid);
if(x<=mid) return find(root<<1,l,mid,x);
return find(root<<1|1,mid+1,r,x);
}
int main()
{
int x,y,i;
scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%d",&a[i]);
for(i=1;i<n;++i)
{
scanf("%d%d",&x,&y);
edge(x,y),edge(y,x);
}
point(1,1);
dfs1(1);
dfs2(1);
modify(1,1,n,pos[a[1]],pos[a[1]],1);
modify(1,1,n,pos[a[n]],pos[a[n]],-1);
for(i=1;i<n;++i) revise(a[i],a[i+1]);
for(i=1;i<=n;++i) printf("%d\n",find(1,1,n,pos[i]));
return 0;
}