首先可以初步判断这个题肯定要计算LCA,我们、就写个简单的倍增只会这个吧,使用链式前向星存储边。
选择1号结点开始dfs
dfs过程中计算up[ ][ ]数组(up[x][i]表示 x 结点的 2^i代祖先是谁)和deep[ ]数组(deep[x]表示结点 x 在树中的深度)
然后我们不从运动员入手,而是枚举观察员。看看哪些结点会为这个观察员i做贡献(刚好在wi秒跑到他这儿)。
大头戏来了
AC代码
#include<algorithm> #include<bitset> #include<cctype> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<list> #include<map> #include<queue> #include<set> #include<stack> #include<string> #include<typeinfo> #include<vector> #define maxn 900000//本蒟蒻到现在都想不通为什么要开这么大 using namespace std; struct node1 { int begin,end,lca,len; }p[maxn]; struct node2 { int next,to; }q[maxn*2]; struct node3 { int nxt,v; }q1[maxn*4]; struct node4 { int ct1,ct2; }o[maxn*2];//本蒟蒻觉得结构体好理解就写了四个 //当然大佬们的思维肯定不需要 int n, m,cnt,cnt1,val[maxn]; int first[maxn],ans[maxn]; int ins1[maxn],del1[maxn],ins2[maxn],del2[maxn]; int deep[maxn],up[maxn][20];//最重要的的两个数组 inline void add(int a,int b) { q[++cnt].next=first[a]; q[cnt].to=b; first[a]=cnt; }//链式前向星存边 inline void add1(int a,int b,int c) { q1[++cnt1].nxt=ins1[a]; q1[cnt1].v=c; ins1[a]=cnt1; q1[++cnt1].nxt=del1[b]; q1[cnt1].v=c; del1[b]=cnt1; }//链式前向星存边 inline void add2(int a,int b,int c) { q1[++cnt1].nxt=ins2[a]; q1[cnt1].v=c; ins2[a]=cnt1; q1[++cnt1].nxt=del2[b]; q1[cnt1].v=c; del2[b]=cnt1; }//链式前向星存边 void dfs(int x) { for(int i=1;(1<<i)<=deep[x];i++) up[x][i]=up[up[x][i-1]][i-1]; for(int i=first[x];i;i=q[i].next) { if(q[i].to==up[x][0]) continue; up[q[i].to][0]=x; deep[q[i].to]=deep[x]+1; dfs(q[i].to); } }//建树,预处理fa[][]数组, 计算deep[]数组 inline void dfs1(int x) { ans[x]=-o[deep[x]+val[x]].ct1-o[deep[x]-val[x]+n].ct2; for(int i=first[x];i;i=q[i].next) { if(q[i].to==up[x][0]) continue; dfs1(q[i].to); } for(int i=ins1[x];i;i=q1[i].nxt) o[q1[i].v].ct1++; for(int i=del1[x];i;i=q1[i].nxt) o[q1[i].v].ct1--; for(int i=ins2[x];i;i=q1[i].nxt) o[q1[i].v+n].ct2++; for(int i=del2[x];i;i=q1[i].nxt) o[q1[i].v+n].ct2--; ans[x]+=o[deep[x]+val[x]].ct1+o[deep[x]-val[x]+n].ct2; }//找“贡献” int main() { freopen("running.in","r",stdin); freopen("running.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b),add(b,a); } deep[1]=1; dfs(1); for(int i=1;i<=n;i++) scanf("%d",&val[i]); for(int i=1;i<=m;i++) scanf("%d%d",&p[i].begin,&p[i].end); for(int i=1;i<=m;i++) { int x=p[i].begin,y=p[i].end; if(deep[x]<deep[y]) swap(x,y); if(deep[x]!=deep[y]) for(int i=18;i>=0;i--) if(deep[up[x][i]]>=deep[y]) x=up[x][i]; if(x!=y) { for(int j=18;j>=0;j--) if(up[x][j]!=up[y][j]) x=up[x][j],y=up[y][j]; x=up[x][0]; } p[i].lca=x; p[i].len=deep[p[i].begin]-deep[x]+deep[p[i].end]-deep[x]; }//ICA(x和y的最近公共祖先) 实在不想再开函数了,而且这样显得主函数没那么空虚 for(int i=1;i<=m;i++) { add1(p[i].begin,up[p[i].lca][0],deep[p[i].begin]); add2(p[i].end,p[i].lca,deep[p[i].end]-p[i].len); } dfs1(1); for(int i=1;i<=n;i++) printf("%d ",ans[i]);//完美输出 //终于结束了 QAQ return 0; }