1. 程式人生 > 其它 >#點分樹#洛谷 6626 [省選聯考 2020 B 卷] 訊息傳遞

#點分樹#洛谷 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;
}