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
51 4 5 3 2
1 2
2 4
2 3
4 5
Sample Output
12
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;
}
相关文章推荐
- bzoj 3631 [JLOI2014]松鼠的新家
- BZOJ3631: [JLOI2014]松鼠的新家
- bzoj 3631 [JLOI2014]松鼠的新家
- bzoj3631[JLOI2014]松鼠的新家 树链剖分
- 【BZOJ 3631】 [JLOI2014]松鼠的新家
- 【bzoj3631】[JLOI2014]松鼠的新家
- BZOJ 3631 【JLOI2014】 松鼠的新家
- 【BZOJ 3631】【JLOI 2014】松鼠的新家【树链剖分】
- BZOJ 3631: [JLOI2014]松鼠的新家 树上差分
- [BZOJ] 3631: [JLOI2014]松鼠的新家
- [Bzoj3631][JLOI2014]松鼠的新家 (树上前缀和)
- [bzoj 3631--JLOI2014]松鼠的新家
- [BZOJ3631] [JLOI2014] 松鼠的新家
- bzoj 3631: [JLOI2014]松鼠的新家 树链剖分
- BZOJ3631 [JLOI2014]松鼠的新家(树链剖分)
- BZOJ3631[JLOI2014]松鼠的新家 题解
- [bzoj3631][JLOI2014]松鼠的新家 树上差分
- 【BZOJ3631】[JLOI2014]松鼠的新家 树链剖分
- BZOJ 3631 [JLOI2014]松鼠的新家==树剖
- 【bzoj 3631】[JLOI2014]松鼠的新家(树链剖分)