音乐播放器
HMF-have much fun Site
 
文章 标签
16

Powered by Gridea | Theme: Fog
载入天数...
载入时分秒...
总访问量:  |   访问人数:

【题解】P6626 [省选联考 2020 B 卷] 消息传递

  热度: loading...

模板题。

询问形如对一个点求距离它为 kk 的点有多少个,典型的与树形态无关的问题,考虑点分治。

将询问挂到点上,每次对于分支中心 dfs,记录下距离分治中心为 disdis 的点的总数,再记录下距离分治中心为 disdis,且在分治中心的儿子 ii 子树里的点的总数。答案为与询问点在不同子树中,且距离分治中心为询问距离减去询问点到分治中心距离的点。设询问点到分治中心的距离为 dd ,考虑容斥,总答案为距离询问中心距离为 dd 的点的总数减去与询问点在同一子树内且距离分治中心为 dd 的点的总数,用 map 统计即可。

#include<bits/stdc++.h>
#define N 100010
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
int T,n,m;
typedef pair<int,int> pii;
int read() {
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) f=ch=='-'?-1:1,ch=getchar();
	while(isdigit(ch)) res=res*10+ch-'0',ch=getchar();
	return f*res;
}
int cnt,head[N],to[N<<1],nxt[N<<1];
vector<pii> qu[N]; 
int vis[N],siz[N],son[N],rt,S,ans[N];
void insert(int u,int v){
	cnt++;
	to[cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
} 
void gtrt(int now,int fa) {
//	cout<<now<<endl;
	siz[now]=1,son[now]=0;
	for(int i=head[now]; i; i=nxt[i]) 
	    if(!vis[to[i]]&&to[i]!=fa) {
	    	gtrt(to[i],now);
	    	siz[now]+=siz[to[i]];
	    	son[now]=max(son[now],siz[to[i]]);
		}
	son[now]=max(son[now],S-siz[now]);
	if(son[now]<son[rt]) rt=now;
}
struct node{
	int dis,id,fr;
	bool operator <(const node o) const{return dis==o.dis?fr<o.fr:dis<o.dis;}
}sk[N],q[N];
int tp,qn,bac[N];
map<pii,int> cot;
void dfs(int now,int fa,int dis,int fr) {
	cot[mp(fr,dis)]++,bac[dis]++;
	for(int i=0,sz=qu[now].size(); i<sz; i++) q[++qn]=node{qu[now][i].fi-dis,qu[now][i].se,fr};
	for(int i=head[now]; i; i=nxt[i])
	    if(!vis[to[i]]&&to[i]!=fa) dfs(to[i],now,dis+1,(fr==0)?to[i]:fr);
}
void clean(int now,int fa,int dis) {
	bac[dis]--;
	for(int i=head[now]; i; i=nxt[i])
	    if(!vis[to[i]]&&to[i]!=fa) clean(to[i],now,dis+1);
}
void solve(int now) {
	vis[now]=1;
	tp=qn=0,cot.clear(),dfs(now,0,0,0);
	for(int i=1; i<=qn; i++) if(q[i].dis>=0) 
		ans[q[i].id]+=bac[q[i].dis]-cot[mp(q[i].fr,q[i].dis)];
  	clean(now,0,0);
	int tmp=S;
	for(int i=head[now]; i; i=nxt[i]) if(!vis[to[i]]) {
		S=siz[to[i]]<siz[now]?siz[to[i]]:tmp-siz[now];
		rt=0,gtrt(to[i],now),solve(rt);
	} 
}
int main()
{
	T=read();
	while(T--) {
		cnt=0;
		for(int i=1; i<=n; i++) qu[i].clear();
		memset(vis,0,sizeof(vis));
		memset(ans,0,sizeof(ans));
		memset(head,0,sizeof(head));
		n=read(),m=read();
		for(int i=1; i<n; i++) {
			int u=read(),v=read();
			insert(u,v);
			insert(v,u);
		}
		for(int i=1; i<=m; i++) {
			int x=read(),k=read();
			if(!k) ans[i]=1;
			else qu[x].pb(mp(k,i));
		}
		son[0]=S=n,rt=0,gtrt(1,0),solve(rt);
		for(int i=1; i<=m; i++) cout<<ans[i]<<endl;
	}
 }