您的位置:首页 > 其它

BZOJ 3631 [JLOI2014]松鼠的新家

2017-04-16 13:07 405 查看

Description

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

Input

第一行一个整数n,表示房间个数
第二行n个整数,依次描述a1-an
接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

Output

一共n行,第i行输出标号为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 <=300000

刚学树剖,去做lnoi,一脸懵逼,听popoqqq大爷说jloi的简单,就来水了。

想也不想就剖了,一个迷之小错,调了一上午。b站水过,luogu一个点超时。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n,mct,dcnt,a
,hd
;
struct edge
{
int to,nxt;
}v[2*N];
struct node
{
int son,dep,fa,sz,w,tp;
}tr
;
struct segtree
{
int l,r,tag,sum;
}st[4*N];
void addedge(int x,int y)
{
v[++mct].to=y;
v[mct].nxt=hd[x];
hd[x]=mct;
}
void dfs1(int u)
{
tr[u].sz=1;
for(int i=hd[u];i;i=v[i].nxt)
if(v[i].to!=tr[u].fa)
{
tr[v[i].to].dep=tr[u].dep+1;
tr[v[i].to].fa=u;
dfs1(v[i].to);
tr[u].sz+=tr[v[i].to].sz;
if(tr[v[i].to].sz>tr[tr[u].son].sz)
tr[u].son=v[i].to;
}
}
void dfs2(int u,int top)
{
tr[u].tp=top;
tr[u].w=++dcnt;
if(tr[u].son)
{
dfs2(tr[u].son,top);
for(int i=hd[u];i;i=v[i].nxt)
if(v[i].to!=tr[u].son&&v[i].to!=tr[u].fa)
dfs2(v[i].to,v[i].to);
}
}
void pushup(int num)
{
st[num].sum=st[2*num].sum+st[2*num+1].sum;
}
void pushdown(int num)
{
if(st[num].tag)
{
if(st[num].l!=st[num].r)
{
st[2*num].sum+=(st[2*num].r-st[2*num].l+1)*st[num].tag;
st[2*num+1].sum+=(st[2*num+1].r-st[2*num+1].l+1)*st[num].tag;
st[2*num].tag+=st[num].tag;
st[2*num+1].tag+=st[num].tag;
}
st[num].tag=0;
}
}
void build(int num,int l,int r)
{
st[num].l=l,st[num].r=r;
if(l==r)
return ;
int mid=(l+r)/2;
build(2*num,l,mid),build(2*num+1,mid+1,r);
}
void change(int num,int x,int y,int z)
{
if(st[num].l>y||st[num].r<x)
return ;
if(st[num].l>=x&&st[num].r<=y)
{
st[num].sum+=(st[num].r-st[num].l+1)*z;
st[num].tag+=z;
return ;
}
pushdown(num);
change(2*num,x,y,z),change(2*num+1,x,y,z);
pushup(num);
}
void add(int x,int y)
{
while(tr[x].tp!=tr[y].tp)
{
if(tr[tr[x].tp].dep>tr[tr[y].tp].dep)
{
change(1,tr[tr[x].tp].w,tr[x].w,1);
x=tr[tr[x].tp].fa;
}
else
{
change(1,tr[tr[y].tp].w,tr[y].w,1);
y=tr[tr[y].tp].fa;
}
}
if(tr[x].dep<tr[y].dep)
change(1,tr[x].w,tr[y].w,1);
else
change(1,tr[y].w,tr[x].w,1);
}
int query(int num,int x)//ѯÎÊxµÄÖµ
{
if(st[num].l==st[num].r)
return st[num].sum;
pushdown(num);
if(x<=st[2*num].r)
return query(2*num,x);
return query(2*num+1,x);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y),addedge(y,x);
}
dfs1(1);
dfs2(1,1);
build(1,1,n);
for(int i=2;i<=n;i++)//ÿ´Î²»È¥µÚi¸öµã
add(a[i-1],a[i]);
for(int i=1;i<=n;i++)
{
int ans=query(1,tr[i].w);
if(i!=a[1])
ans--;
printf("%d\n",ans);
}
return 0;
}

窝不服啊,想到这题和最大流(假的)差不多,抄了一下之前写的差分,终于在luogu过了。短小精悍,跑得快,差分大赞。

#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n,mct,a
,hd
,dep
,f
[20],ans
;
struct edge
{
int to,nxt;
}v[2*N];
void addedge(int x,int y)
{
v[++mct].to=y;
v[mct].nxt=hd[x];
hd[x]=mct;
}
void init(int u,int fa)
{
dep[u]=dep[fa]+1;
f[u][0]=fa;
for(int i=hd[u];i;i=v[i].nxt)
if(v[i].to!=fa)
init(v[i].to,u);
}
int lca(int a,int b)
{
if(dep[a]<dep[b])
swap(a,b);
for(int i=19;i>=0;i--)
if(dep[f[a][i]]>=dep[b])
a=f[a][i];
if(a==b)
return a;
for(int i=19;i>=0;i--)
if(f[a][i]!=f[b][i])
a=f[a][i],b=f[b][i];
return f[a][0];
}
void dfs(int u,int fa)
{
for(int i=hd[u];i;i=v[i].nxt)
if(v[i].to!=fa)
{
dfs(v[i].to,u);
ans[u]+=ans[v[i].to];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y),addedge(y,x);
}
init(1,0);
for(int i=1;i<=19;i++)
for(int j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];
for(int i=2;i<=n;i++)
{
int x=lca(a[i-1],a[i]);
ans[a[i-1]]++,ans[a[i]]++,ans[x]--,ans[f[x][0]]--;
}
dfs(1,0);
for(int i=1;i<=n;i++)
printf("%d\n",i==a[1]?ans[i]:ans[i]-1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树链剖分