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