3631: [JLOI2014]松鼠的新家
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1486 Solved: 727
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
1 4 5 3 2
1 2
2 4
2 3
4 5
Sample Output
2
1
2
1
HINT
2<= n <=300000
解题思路:问题可以转化为对树上的路径进行加1,最后求单点。所以可以用树链剖分
然后加1可以转化到区间上,用前缀和的思想来做,在开头+1,末尾-1,然后一路求过
来就可以了。
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int len,cnt,n;
int to[610000],next[610000],h[610000];
int deep[310000],top[310000],fa[310000],size[310000],son[310000];
int me[310000],xv[310000];
int dui[310000],ans[310000],Ans[310000];
int ad[310000],ji[310000];
inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}
void insert(int x,int y)
{
++len; to[len]=y; next[len]=h[x]; h[x]=len;
}
void dfs(int now,int from,int dep)
{
deep[now]=dep; fa[now]=from; size[now]=1; son[now]=0;
int u=h[now];
while (u!=0)
{
if (to[u]!=from)
{
dfs(to[u],now,dep+1);
size[now]+=size[to[u]]; if (size[to[u]]>size[son[now]]) son[now]=to[u];
}
u=next[u];
}
}
void dfs1(int now,int tg)
{
++cnt; me[cnt]=now; xv[now]=cnt;
if (tg==-1) tg=now; top[now]=tg;
if (son[now]==0) return;
dfs1(son[now],tg);
int u=h[now];
while (u!=0)
{
if (to[u]!=fa[now] && to[u]!=son[now])
{
dfs1(to[u],-1);
}
u=next[u];
}
}
int main()
{
n=read();
for (int i=1;i<=n;++i)
{
int x=read(); dui[x]=i;
}
for (int i=1;i<=n-1;++i)
{
int x,y;
x=read(); y=read();
x=dui[x]; y=dui[y];
insert(x,y); insert(y,x);
}
dfs(1,0,0);
cnt=0;
dfs1(1,-1);
for (int i=2;i<=n;++i)
{
int x=i-1; int y=i;
while (top[x]!=top[y])
{
if (deep[top[x]]>=deep[top[y]]) ad[xv[top[x]]]+=1,ji[xv[x]]+=1,x=fa[top[x]];else
ad[xv[top[y]]]+=1,ji[xv[y]]+=1,y=fa[top[y]];
}
if (deep[x]<deep[y]) ad[xv[x]]+=1,ji[xv[y]]+=1;else
ad[xv[y]]+=1,ji[xv[x]]+=1;
}
int now=0;
for (int i=1;i<=n;++i)
{
now+=ad[i]; ans[me[i]]=now; now-=ji[i];
if (i!=1) ans[me[i]]-=1;
}
for (int i=1;i<=n;++i)
{
printf("%d\n",ans[dui[i]]);
}
int opp=n+1;
}