bzoj3631[JLOI2014]松鼠的新家

bzoj3631[JLOI2014]松鼠的新家

题意:

给个n点树,再给个节点的游览顺序,每经过一个节点(包括上一个游览的点到下一个游览的点路径上的点)就可以从这个节点拿走一个糖,问所有节点一开始要放几个糖。最后到达的节点不用糖。n≤300000

题解:

链剖将树链排成一列,然后用数组区间加的方式(即在数组区间左端点位置增加值,数组区间右端点+1位置增加这个值的相反数,最后扫一遍a[i]+=a[i-1])累计糖果数。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 300100
 5 #define inc(i,j,k) for(int i=j;i<=k;i++)
 6 using namespace std;
 7 
 8 inline int read(){
 9     char ch=getchar(); int f=1,x=0;
10     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
11     return x*f;
12 }
13 struct e{int t,n;}; e es[maxn*2]; int g[maxn],ess;
14 void pe(int f,int t){
15     es[++ess]=(e){t,g[f]}; g[f]=ess; es[++ess]=(e){f,g[t]}; g[t]=ess;
16 }
17 void init(){ess=0; memset(g,0,sizeof(g));}
18 int n,fa[maxn],dep[maxn],go[maxn],pos[maxn],top[maxn],sz[maxn],sm[maxn],tot;
19 void dfs1(int x,int f){
20     sz[x]=1; 
21     for(int i=g[x];i;i=es[i].n)if(es[i].t!=f){
22         dep[es[i].t]=dep[x]+1; fa[es[i].t]=x;
23         dfs1(es[i].t,x); sz[x]+=sz[es[i].t];
24     }
25 }
26 void dfs2(int x,int f,int tp){
27     pos[x]=++tot; top[x]=tp; int mx=0;
28     for(int i=g[x];i;i=es[i].n)if(es[i].t!=f){
29         if(!mx||sz[mx]<sz[es[i].t])mx=es[i].t;
30     }
31     if(!mx)return; dfs2(mx,x,tp);
32     for(int i=g[x];i;i=es[i].n)if(es[i].t!=f&&es[i].t!=mx){
33         dfs2(es[i].t,x,es[i].t);
34     }
35 }
36 void lca(int x,int y){
37     for(;top[x]!=top[y];sm[pos[top[x]]]++,sm[pos[x]+1]--,x=fa[top[x]])
38         if(dep[top[x]]<dep[top[y]])swap(x,y);
39     if(dep[x]>dep[y])swap(x,y); sm[pos[x]]++,sm[pos[y]+1]--;
40 }
41 int main(){
42     n=read(); inc(i,1,n)go[i]=read(); init();
43     inc(i,1,n-1){int a=read(),b=read(); pe(a,b);}
44     dep[1]=0; fa[1]=0; tot=0; dfs1(1,0); dfs2(1,0,1);
45     inc(i,1,n){
46         if(i==1){sm[pos[go[i]]]++; sm[pos[go[i]]+1]--; continue;}
47         sm[pos[go[i-1]]]--; sm[pos[go[i-1]]+1]++; lca(go[i-1],go[i]);
48         if(i==n){sm[pos[go[i]]]--; sm[pos[go[i]]+1]++;}
49     }
50     inc(i,1,tot)sm[i]+=sm[i-1]; inc(i,1,n)printf("%d\n",sm[pos[i]]);
51     return 0;
52 }

 

20160610

转载于:https://www.cnblogs.com/YuanZiming/p/5778209.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值