【虚数】BZOJ3572[HNOI2014]世界树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/88951350

题意:

给出一颗树,每次选中m个点,对于树上任意一个点,会被其最近的一个选中点包含(相同有编号小优先),求每个选中点包含了多少个点。


分析:

之前写过两次都没写博客。。

结果复习板题的时候,连题意都不知道。。。

方法就是虚数板子

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 300010
#define INF 0x3FFFFFFF
using namespace std;
typedef pair<int,int> pii;
int dfn[MAXN],ncnt,Q;
int dep[MAXN],siz[MAXN],ans[MAXN],flag[MAXN];
int fa[MAXN][20];
vector<int> a[MAXN],son[MAXN];
void dfs(int x,int f=0){
	dep[x]=dep[f]+1;
	fa[x][0]=f;
	for(int i=1;i<20;i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	dfn[x]=++ncnt;	
	siz[x]=1;
	for(int i=0;i<int(a[x].size());i++){
		int u=a[x][i];
		if(u==f)
			continue;
		dfs(u,x);
		siz[x]+=siz[u];
	}
}
int find_child(int x,int u){
	for(int i=19;i>=0;i--)
		if(dep[fa[u][i]]>dep[x])
			u=fa[u][i];
	return u;
}
pii near[MAXN];
void get_near(int x){
	if(flag[x]==Q)
		near[x]=make_pair(0,x);
	else
		near[x]=make_pair(INF,0);
	for(int i=0;i<int(son[x].size());i++){
		int u=son[x][i];
		get_near(u);
		pii res=near[u];
		res.first+=(dep[u]-dep[x]);
		near[x]=min(near[x],res);
	}
}
void get_near(int x,pii upd){
	near[x]=min(near[x],upd);
	for(int i=0;i<int(son[x].size());i++){
		int u=son[x][i];
		pii upd1=near[x];
		upd1.first+=(dep[u]-dep[x]);	
		get_near(u,upd1);
	}
}
void calc(int x){
	int siz1=siz[x];
	for(int i=0;i<int(son[x].size());i++){
		int u=son[x][i];
		calc(u);
		int sonc=find_child(x,u);
		siz1-=siz[sonc];
		int ax=near[u].second,bx=near[x].second;
		if(ax==bx){
			ans[bx]+=(siz[sonc]-siz[u]);
			continue;
		}
		int tp=u;
		int q=near[u].first;
		int p=near[x].first;
		int totlen=p+q+dep[u]-dep[x];
		for(int i=19;i>=0;i--){
			int v=fa[tp][i];
			if(dep[v]>dep[x]&&(dep[u]-dep[v]+q)*2<totlen)
				tp=v;	
		}
		if(totlen%2==0&&ax<bx&&(dep[u]-dep[fa[tp][0]]+q)*2<=totlen)
			tp=fa[tp][0];
		ans[ax]+=(siz[tp]-siz[u]);
		ans[bx]+=(siz[sonc]-siz[tp]);
	}
	ans[near[x].second]+=siz1;
}
void solve(int rt){
	get_near(rt);	
	get_near(rt,near[rt]);
	ans[near[rt].second]+=(siz[1]-siz[rt]);
	calc(rt);
}
bool sort_by_dfn(int x,int y){
	return dfn[x]<dfn[y];	
}
int lca(int u,int v){
	if(dep[u]<dep[v])
		swap(u,v);
	for(int i=19;i>=0;i--)
		if(dep[fa[u][i]]>=dep[v])
			u=fa[u][i];
	if(u==v)
		return u;
	for(int i=19;i>=0;i--)
		if(fa[u][i]!=fa[v][i]){
			u=fa[u][i];
			v=fa[v][i];
		}
	return fa[u][0];
}
int n,u,v,q,tot,rt;
int b[MAXN],id[MAXN],st[MAXN],tp;
void Print(int x){
	PF("%d(%d[%d,%d]) ",x,flag[x]==Q,near[x].first,near[x].second);
	for(int i=0;i<int(son[x].size());i++)
		Print(son[x][i]);
}
int main(){
	SF("%d",&n);
	for(int i=1;i<n;i++){
		SF("%d%d",&u,&v);
		a[u].push_back(v);
		a[v].push_back(u);
	}
	dfs(1);
	SF("%d",&q);
	for(int i=1;i<=q;i++){
		SF("%d",&tot);
		Q++;
		for(int j=1;j<=tot;j++){
			SF("%d",&b[j]);
			id[j]=b[j];
			flag[b[j]]=Q;
		}
		sort(b+1,b+1+tot,sort_by_dfn);
		tp=0;
		st[++tp]=b[1];
		son[b[1]].clear();
		for(int j=2;j<=tot;j++){
			int nx=lca(b[j],st[tp]);
			while(tp>0&&dep[st[tp]]>dep[nx]){
				rt=st[tp--];
				if(tp==0||dep[st[tp]]<dep[nx]){
					st[++tp]=nx;
					son[nx].clear();
				}	
				son[st[tp]].push_back(rt);
			}
			st[++tp]=b[j];
			son[b[j]].clear();
		}
		while(tp){
			rt=st[tp--];
			if(tp)
				son[st[tp]].push_back(rt);
		}
		for(int j=1;j<=tot;j++)
			ans[id[j]]=0;
		solve(rt);
//		Print(rt);
		for(int j=1;j<=tot;j++)
			PF("%d ",ans[id[j]]);
		PF("\n");
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/88951350
今日推荐