题目:BZOJ3631、洛谷P3258。
题目大意:有一棵n个点的树,和一个长度为n的序列a。现在要依次到达$a_1,a_2,a_3,...,a_n$节点,只能沿着树枝走。每次从一个节点到另一个节点,所经过的所有节点的点权加1(每次出发的节点除外,最后一个到达的节点不用+1,但一开始到1号节点要+1)。求最后每个点的点权。
解题思路:树上差分。
每次在一条路径的起点和终点+1,它们的LCA和LCA的父亲-1,最后每个节点的子树和就是最终答案。
注意上述不用加的情况,相当于除了$a_1$,每个节点答案都要-1。
C++ Code:
#include<cstdio> #include<cstring> #include<vector> #include<cctype> using namespace std; #define N 300005 int n,ne=0,nq=0; bool vis[N],instack[N]; int f[N],head[N],que[N],a[N],jz[N],zx[N],p[N]; #define C c=getchar() inline int readint(){ char C; bool b=false; while(!isdigit(c))b=c=='-',C; int d=0; while(isdigit(c)){ d=d*10+c-'0'; C; } return (b)?(-d):d; } struct query{ int same,nxt,to,num; bool flag; }q[600001]; struct edge{ int to,nxt; }e[600001]; void add_edge(int x,int y){ e[++ne].to=y; e[ne].nxt=head[x]; head[x]=ne; e[++ne].to=x; e[ne].nxt=head[y]; head[y]=ne; } void add_que(int x,int y,int z){ q[++nq].to=y; q[nq].same=nq+1; q[nq].num=z; q[nq].nxt=que[x]; que[x]=nq; q[++nq].to=x; q[nq].same=nq-1; q[nq].num=z; q[nq].nxt=que[y]; que[y]=nq; } int find(int x){ if(f[x]==x)return x; return f[x]=find(f[x]); } void tarjan(int root){ instack[root]=true; for(int i=head[root];i;i=e[i].nxt){ int v=e[i].to; if(instack[v])continue; tarjan(v); f[v]=root; vis[v]=true; } for(int i=que[root];i;i=q[i].nxt) if(vis[q[i].to]&&!q[i].flag){ int p=find(q[i].to); --a[p]; --a[zx[p]]; q[i].flag=q[q[i].same].flag=true; } instack[root]=false; } void dfs(int now){ instack[now]=true; for(int i=head[now];i;i=e[i].nxt) if(!instack[e[i].to]){ dfs(e[i].to); a[now]+=a[e[i].to]; } } void dfs2(int now){ instack[now]=true; for(int i=head[now];i;i=e[i].nxt) if(!instack[e[i].to]){ zx[e[i].to]=now; dfs2(e[i].to); } } int main(){ n=readint(); memset(vis,0,sizeof(vis)); memset(instack,0,sizeof instack); for(int i=1;i<=n;i++)f[i]=i,p[i]=readint(); for(int i=1;i<n;i++){ int u=readint(),v=readint(); add_edge(u,v); } memset(a,0,sizeof a); zx[1]=0; dfs2(1); memset(instack,0,sizeof instack); for(int i=1;i<n;i++){ int x=p[i],y=p[i+1]; ++a[x]; ++a[y]; add_que(x,y,i); } tarjan(1); memset(instack,0,sizeof instack); dfs(1); ++a[p[1]]; for(int i=1;i<=n;i++) printf("%d ",a[i]-1); return 0; }