Description
A 国有n 个城市,城市之间有一些双向道路相连,并且城市两两之间有唯一
路径。现在有火车在城市 a,需要经过m 个城市。火车按照以下规则行驶:每次
行驶到还没有经过的城市中在 m 个城市中最靠前的。现在小 A 想知道火车经过
这m 个城市后所经过的道路数量。
Input
第一行三个整数 n、m、a,表示城市数量、需要经过的城市数量,火车开始
时所在位置。
接下来 n-1 行,每行两个整数 x和y,表示 x 和y之间有一条双向道路。
接下来一行 m 个整数,表示需要经过的城市。
Output
一行一个整数,表示火车经过的道路数量。
树链剖分+树状数组维护每个点被经过了几次,然后就是模拟了
#include<cstdio> const int M=30000000; char buf[M+4],*ptr=buf-1; inline int _int(){ int x=0,c=*++ptr; while(c>57||c<48)c=*++ptr; while(c>47&&c<58)x=x*10+c-48,c=*++ptr; return x; } const int N=500010; int n,m,a; long long ans=0; int es[N*2],enx[N*2],e0[N],ep=2; int sz[N],son[N],top[N],fa[N],dep[N],id[N],bit[N],idp=0; void f1(int w,int pa){ dep[w]=dep[pa]+1; sz[w]=1; fa[w]=pa; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=pa){ f1(u,w); sz[w]+=sz[u]; if(sz[son[w]]<sz[u])son[w]=u; } } } void f2(int w,int tp){ id[w]=++idp; top[w]=tp; if(son[w])f2(son[w],tp); for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u!=fa[w]&&u!=son[w])f2(u,u); } } void inc(int w,int v){ while(w<=idp)bit[w]+=v,w+=w&-w; } int get(int w){ int s=0; while(w)s+=bit[w],w-=w&-w; return s; } void lca(int x,int y){ ans+=dep[x]+dep[y]; int a=top[x],b=top[y],c; while(a!=b){ if(dep[a]<dep[b])c=a,a=b,b=c,c=x,x=y,y=c; inc(id[x]+1,-1);inc(id[a],1); x=fa[a];a=top[x]; } if(dep[x]<dep[y]){ ans-=dep[x]<<1; inc(id[x],1);inc(id[y]+1,-1); }else{ ans-=dep[y]<<1; inc(id[y],1);inc(id[x]+1,-1); } } int main(){ fread(buf,1,M,stdin); n=_int();m=_int();a=_int(); for(int i=1;i<n;i++){ int a=_int(),b=_int(); es[ep]=b;enx[ep]=e0[a];e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } f1(1,0);f2(1,1);++idp; for(int i=0;i<m;i++){ int x=_int(); if(!get(id[x])){ lca(a,x); a=x; } } printf("%lld\n",ans); return 0; }