您的位置:首页 > 其它

BZOJ3631[JLOI2014]松鼠的新家 题解

2016-08-03 18:21 267 查看
题目大意:

  给你一棵树,要从编号为a[1]的节点走到编号为a[2]的节点再走到编号为a[3]的节点……一直走到编号为a
的节点。问每个节点最少访问多少次。

思路:

  将其进行轻重链剖分,则从a[i]走到a[i+1]实际上就是在几段重链的节点上+1,于是就用线段树来维护一下即可。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 1200000
using namespace std;

int ans[M],to[M],head[M],next[M],vis[M],size[M],deep[M],id[M],top[M],sum[M],fa[M],a[M],cnt,dfn,n;

void add(int x,int y)
{
to[++cnt]=y;
next[cnt]=head[x];
head[x]=cnt;
}

void dfs1(int x)
{
size[x]=vis[x]=1;
for (int i=head[x];i;i=next[i])
if (!vis[to[i]])
{
deep[to[i]]=deep[x]+1;
fa[to[i]]=x;
dfs1(to[i]);
size[x]+=size[to[i]];
}
}

void dfs2(int x,int chain)
{
int k=0,i;
id[x]=++dfn;
top[x]=chain;
for (i=head[x];i;i=next[i])
if (deep[to[i]]>deep[x] && size[to[i]]>size[k]) k=to[i];
if (!k) return;
dfs2(k,chain);
for (i=head[x];i;i=next[i])
if (deep[to[i]]>deep[x] && to[i]!=k) dfs2(to[i],to[i]);
}

void push_down(int cur)
{
sum[cur<<1]+=sum[cur];
sum[cur<<1|1]+=sum[cur];
sum[cur]=0;
}

void ADD(int L,int R,int l,int r,int cur)
{
if (l<=L && r>=R)
{
sum[cur]++;
return;
}
push_down(cur);
int mid=L+R>>1;
if (l>mid) ADD(mid+1,R,l,r,cur<<1|1);
else if (r<=mid) ADD(L,mid,l,r,cur<<1);
else ADD(L,mid,l,mid,cur<<1),ADD(mid+1,R,mid+1,r,cur<<1|1);
}

int ask(int l,int r,int x,int cur)
{
if (l==r) return sum[cur];
push_down(cur);
int mid=l+r>>1;
if (x>mid) return sum[cur]+ask(mid+1,r,x,cur<<1|1);
else return sum[cur]+ask(l,mid,x,cur<<1);
}

void Add(int x,int y)
{
for (;top[x]!=top[y];x=fa[top[x]])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
ADD(1,n,id[top[x]],id[x],1);
}
if (deep[x]<deep[y]) swap(x,y);
ADD(1,n,id[y],id[x],1);
}

int main()
{
int i,x,y;
scanf("%d",&n);
for (i=1;i<=n;i++) scanf("%d",&a[i]);
for (i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs1(1);
dfs2(1,1);
for (i=1;i<n;i++) Add(a[i],a[i+1]);
for (i=1;i<=n;i++)
{
ans[i]=-(i!=a[1]);
ans[i]+=ask(1,n,id[i],1);
}
for (i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: