#点分树#洛谷 6626 [省选联考 2020 B 卷] 消息传递
题目
多组数据多组询问,对于一个点 \(x\) 和 树上的距离 \(k\),问 \(\sum_{i=1}^n[Dis(x,i)==k]\)
分析
卡了一页的常,发现两个 \(\log\) 过不去,有一个技巧就是 vector 的 resize 函数,
点分树有一个性质,子树的深度不超过子树大小的一半,反正直接用 vector 就行了
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#define register
using namespace std;
const int N=100011; bool v[N]; struct node{int y,next;}e[N<<1];
int big[N],siz[N],SIZ,dfn[N],Siz[N],fat[N],root,n,m,as[N],tot;
int dep[N],et=1,two[18],lg[N<<1],f[N<<1][18]; vector<int>K[N][2];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void Max(int &a,int b){a=a>b?a:b;}
void Min(int &a,int b){a=a<b?a:b;}
int Get_Min(int x,int y){return dep[x]<dep[y]?x:y;}
int lca(int x,int y){
if (x>y) x^=y,y^=x,x^=y; int z=lg[y-x+1];
return Get_Min(f[x][z],f[y-two[z]+1][z]);
}
int Dis(int x,int y){
int LCA=lca(dfn[x],dfn[y]);
return dep[x]+dep[y]-2*dep[LCA];
}
void dfs(int x,int fa){
siz[x]=1,big[x]=0;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y]){
dfs(e[i].y,x);
siz[x]+=siz[e[i].y];
Max(big[x],siz[e[i].y]);
}
Max(big[x],SIZ-siz[x]);
if (big[x]<=big[root]) root=x;
}
void dp(int x){
v[x]=1,Siz[x]=(big[0]>>1)+1;
for (int i=as[x];i;i=e[i].next)
if (!v[e[i].y]){
big[0]=SIZ=siz[e[i].y];
dfs(e[i].y,root=0),
fat[root]=x,dp(root);
}
}
void Dfs(int x,int fa){
f[dfn[x]=++tot][0]=x,dep[x]=dep[fa]+1;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa)
Dfs(e[i].y,x),f[++tot][0]=x;
}
void Update(int x){
int now=x;
for (;now;now=fat[now]){
++K[now][0][Dis(now,x)];
if (fat[now]) ++K[now][1][Dis(fat[now],x)];
}
}
int Query(int x,int y){
int now=x,ans=0;
if (y<=Siz[x]) ans=K[now][0][y];
for (;fat[now];now=fat[now]){
int d=Dis(x,fat[now]),t=y-d;
if (t<0||t>Siz[fat[now]]) continue;
ans+=K[fat[now]][0][t]-K[now][1][t];
}
return ans;
}
int main(){
lg[0]=-1,two[0]=1;
for (int i=1;i<21;++i) two[i]=two[i-1]<<1;
for (int i=1;i<N*2;++i) lg[i]=lg[i>>1]+1;
for (int T=iut();T;--T){
n=iut(),m=iut(),et=1,tot=0;
for (int i=1;i<n;++i){
int x=iut(),y=iut();
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
big[0]=SIZ=n,Dfs(1,0);
for (int j=1;j<=lg[tot];++j)
for (int i=1;i+two[j]-1<=tot;++i)
f[i][j]=Get_Min(f[i][j-1],f[i+two[j-1]][j-1]);
dfs(1,root=0),dfs(root,0),dp(root);
for (int i=1;i<=n;++i) K[i][0].resize(Siz[i]+1),K[i][1].resize(Siz[fat[i]]+1);
for (int i=1;i<=n;++i) Update(i);
for (int i=1;i<=m;++i){
int x=iut(),y=iut();
print(Query(x,y)),putchar(10);
}
for (int i=1;i<=n;++i) as[i]=fat[i]=v[i]=0,K[i][0].clear(),K[i][1].clear();
}
return 0;
}

浙公网安备 33010602011771号