[JLOI2014]松鼠的新家
题目: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\n",a[i]-1);
return 0;
}

浙公网安备 33010602011771号