首先处理出数组mn[x],表示x到离他最近的叶子的距离。如果给定起始位置u,我们以u为根,处理出dis[x]表示x到u的距离,则节点x对答案有贡献当且仅当mn[x]<=dis[x]&&mn[fa[x]]> dis[fa[x]]。我们发现所有满足mn[x]<=dis[x]的点x构成的集合S就是由若干颗子树构成的。(除非起点u为叶子,则集合S就是这棵树本身,只含有一棵树,要特判掉)。
且答案就是子树个数。如何计算子树个数呢?我们处理出每个点的度数deg,我们发现一棵子树的所有点的 ∑v2−deg[v]=1 ∑ v 2 − d e g [ v ] = 1 (因为一棵k个点的子树的度数和为2k-1)。于是我们可以通过计算出所有的点v的 ∑v2−deg[v] ∑ v 2 − d e g [ v ] 得到子树个数。
于是我们就是要从u为根转移到v为根时,维护这个集合S,以及这个和。我们发现这一转移的影响就是:对v的子树的dis都-1,其他点的dis都+1。于是我们可以先做出dfs序,把子树对应到区间,然后区间加法。可以对dfs序分块,每一块维护一个BIT来实现。时间复杂度 O(nn−−√logn) O ( n n l o g n ) 。空间复杂度 O(2nn−−√) O ( 2 n n ) ,bzoj上空间开不下,时间跑不出。。。
还有一种比较优越的点分治做法,可以做到 O(nlogn) O ( n l o g n ) ,待更新。
upd:orz Pickupwin sro orz Pickupwin sro
sbw巨佬太神了。我们先默认给每个答案加上所有点的贡献,其实就是2。然后我们来减去那些不合法的点的贡献。
我们点分治。每次处理出到重心的距离dis。则dis[x]+dis[B]< mn[x]时,x对B的贡献是不合法的。即dis[B]< mn[x]-dis[x].
于是我们可以先dfs一遍把所有的mn[x]-dis[x]的贡献统计进一个数组。然后再dfs一遍枚举B,减去所有不合法的贡献,即>dis[B]的数组的后缀和。注意容斥掉x,B在同一棵子树的情况。
dfs序分块+BIT
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 70010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,h[N],num=0,mn[N],dis[N],fa[N],du[N],in[N],out[N],dfn=0;
int nn,bel[N],lazy[270],alllazy=0,c[270][100010],v[N],w[N],ans[N];
struct edge{
int to,next;
}data[N<<1];
inline void add(int id,int x,int val){for(;x<=n*2+1;x+=x&-x) c[id][x]+=val;}
inline int ask(int id,int x){int res=0;for(;x;x-=x&-x) res+=c[id][x];return res;}
void dfs(int x){
mn[x]=inf;
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==fa[x]) continue;
fa[y]=x;dis[y]=dis[x]+1;dfs(y);mn[x]=min(mn[x],mn[y]+1);
}if(du[x]==1) mn[x]=0;
}
inline void dfs3(int x){
in[x]=++dfn;w[in[x]]=2-du[x];
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==fa[x]) continue;
mn[y]=min(mn[y],mn[x]+1);dfs3(y);
}out[x]=dfn;v[in[x]]=mn[x]-dis[x]+n+1;
add(bel[in[x]],v[in[x]],w[in[x]]);
}
inline int getsum(int x){
if(du[x]==1) return 1;
int res=0;
for(int i=1;i<=bel[n];++i) res+=ask(i,n+1-lazy[i]-alllazy);return res;
}
inline void rebuild(int id,int x,int y,int val){
int l=(id-1)*nn+1,r=min(id*nn,n);
for(int i=l;i<=r;++i) add(id,v[i],-w[i]);
for(int i=l;i<=r;++i) v[i]+=lazy[id];
for(int i=x;i<=y;++i) v[i]+=val;lazy[id]=0;
for(int i=l;i<=r;++i) add(id,v[i],w[i]);
}
inline void change(int x,int y,int val){
if(bel[x]==bel[y]){rebuild(bel[x],x,y,val);return;}
for(int i=bel[x]+1;i<bel[y];++i) lazy[i]+=val;
rebuild(bel[x],x,bel[x]*nn,val);rebuild(bel[y],(bel[y]-1)*nn+1,y,val);
}
void dfs2(int x){
ans[x]=getsum(x);
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==fa[x]) continue;
change(in[y],out[y],2);alllazy--;dfs2(y);
change(in[y],out[y],-2);alllazy++;
}
}
int main(){
// freopen("atlarge.in","r",stdin);
// freopen("atlarge.out","w",stdout);
n=read();nn=sqrt(n);
for(int i=1;i<=n;++i) bel[i]=(i-1)/nn+1;
for(int i=1;i<n;++i){
int x=read(),y=read();du[x]++;du[y]++;
data[++num].to=y;data[num].next=h[x];h[x]=num;
data[++num].to=x;data[num].next=h[y];h[y]=num;
}dfs(1);dfs3(1);dfs2(1);
for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
return 0;
}
点分治
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 70010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,h[N],num=0,ans[N],du[N],mn[N],dis[N],sz[N],f[N],a[N],b[N],mx,tot;
bool vis[N];int mx1=0,sumsz,rt;
struct edge{
int to,next;
}data[N<<1];
void dfs4(int x,int Fa){
mn[x]=inf;if(du[x]==1) mn[x]=0;
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa) continue;
dfs4(y,x);mn[x]=min(mn[x],mn[y]+1);
}
}
void dfs5(int x,int Fa){
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa) continue;
mn[y]=min(mn[y],mn[x]+1);dfs5(y,x);
}
}
void dfs1(int x,int Fa){
sz[x]=1;
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa||vis[y]) continue;
dfs1(y,x);sz[x]+=sz[y];
}
}
void dfs2(int x,int Fa){
f[x]=0;
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa||vis[y]) continue;
dfs2(y,x);f[x]=max(f[x],sz[y]);
}f[x]=max(f[x],sumsz-sz[x]);if(f[x]<f[rt]) rt=x;
}
void dfs3(int x,int Fa){
int d=mn[x]-dis[x];
if(d>0) mx=max(mx,d),a[d]+=2-du[x];
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa||vis[y]) continue;
dis[y]=dis[x]+1;dfs3(y,x);
}
}
void dfs6(int x,int Fa){
int d=mn[x]-dis[x];
if(d>0) mx1=max(mx1,d),b[d]+=2-du[x];
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa||vis[y]) continue;dfs6(y,x);
}
}
void dfs7(int x,int Fa){
ans[x]+=a[dis[x]+1]-b[dis[x]+1];
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(y==Fa||vis[y]) continue;
dfs7(y,x);
}
}
inline void gao(int x){
mx=0;tot=0;dis[x]=0;dfs3(x,0);
for(int i=mx-1;i>=1;--i) a[i]+=a[i+1];
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(vis[y]) continue;
mx1=0;dfs6(y,x);for(int i=mx1-1;i>=1;--i) b[i]+=b[i+1];
dfs7(y,x);for(int i=mx1;i>=1;--i) b[i]=0;
}ans[x]+=a[1];for(int i=mx;i>=1;--i) a[i]=0;
}
inline void solve(int x){
vis[x]=1;dfs1(x,0);gao(x);
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(vis[y]) continue;
sumsz=sz[y];rt=0;dfs2(y,x);solve(rt);
}
}
int main(){
n=read();f[0]=inf;
for(int i=1;i<n;++i){
int x=read(),y=read();du[x]++;du[y]++;
data[++num].to=y;data[num].next=h[x];h[x]=num;
data[++num].to=x;data[num].next=h[y];h[y]=num;
}dfs4(1,0);dfs5(1,0);dfs1(1,0);sumsz=n;rt=0;dfs2(1,0);
solve(rt);
for(int i=1;i<=n;++i){
if(du[i]==1){puts("1");continue;}
printf("%d\n",2-ans[i]);
}return 0;
}