#點分樹#洛谷 6626 [省選聯考 2020 B 卷] 訊息傳遞
阿新 • • 發佈:2021-11-10
點分樹
題目
多組資料多組詢問,對於一個點 \(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; }