bzoj2117 [2010国家集训队]Crash的旅游计划 动态树分治+二分

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/85175429

Description


给定一棵带边权的树,求与x第k近的距离,n<=1e5

Solution


之前碰见过。。当时还不会做的
有一道弱化版的n才1.5e4,可以考虑离线然后区间加、区间第k大,卡一卡说不定能过(滑稽
对于求第k大的问题我们经常考虑二分答案变成判定性问题。建出点分树后每个点开两个vector分别记录到x子树内的点到x的所有距离,x子树内点到fa[x]的所有距离。我们把vector排序然后用二分粗来的答案扔进去二分就行了
这样做是3个log的,每个点只会被塞进log个vector中因此这个暴力非常的优秀。

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int INF=0x3f3f3f3f;
const int N=200000;

struct edge {int y,w,next;} e[N*2];

int dis[N],dep[N],bl[N],size[N],mx[N];
int ls[N],fa[N],acs[N],edCnt,root,sum;

std:: vector <int> vec1[N],vec2[N];

bool del[N];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void add_edge(int x,int y,int w) {
	e[++edCnt]=(edge) {y,w,ls[x]}; ls[x]=edCnt;
	e[++edCnt]=(edge) {x,w,ls[y]}; ls[y]=edCnt;
}

void dfs1(int now) {
	size[now]=1;
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y==fa[now]) continue;
		dep[e[i].y]=dep[now]+1; dis[e[i].y]=dis[now]+e[i].w;
		fa[e[i].y]=now; dfs1(e[i].y); size[now]+=size[e[i].y];
	}
}

void dfs2(int now,int up) {
	int mx=0; bl[now]=up;
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y;
	}
	if (!mx) return ;
	dfs2(mx,up);
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
	}
}

void get_root(int now,int from) {
	size[now]=1; mx[now]=0;
	for (int i=ls[now];i;i=e[i].next) {
		if (del[e[i].y]||e[i].y==from) continue;
		get_root(e[i].y,now); size[now]+=size[e[i].y];
		mx[now]=std:: max(mx[now],size[e[i].y]);
	}
	mx[now]=std:: max(mx[now],sum-size[now]);
	if (mx[now]<mx[root]) root=now;
}

void build(int now) {
	for (int i=ls[now];i;i=e[i].next) {
		if (del[e[i].y]) continue;
		root=0; mx[0]=INF; sum=size[e[i].y];
		get_root(e[i].y,now);
		acs[root]=now; del[root]=1;
		build(root);
	}
}

int get_lca(int x,int y) {
	for (;bl[x]!=bl[y];x=fa[bl[x]]) if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
	return dep[x]<dep[y]?x:y;
}

int get_dis(int x,int y) {
	return dis[x]+dis[y]-dis[get_lca(x,y)]*2;
}

void change(int st) {
	vec1[st].push_back(0);
	for (int x=st;acs[x];x=acs[x]) {
		int dd=get_dis(st,acs[x]);
		vec1[acs[x]].push_back(dd);
		vec2[x].push_back(dd);
	}
}

int check(int st,int mid) {
	int res=std:: upper_bound(vec1[st].begin(),vec1[st].end(),mid)-vec1[st].begin();
	for (int x=st;acs[x];x=acs[x]) {
		int dd=get_dis(st,acs[x]);
		res+=std:: upper_bound(vec1[acs[x]].begin(),vec1[acs[x]].end(),mid-dd)-vec1[acs[x]].begin();
		res-=std:: upper_bound(vec2[x].begin(),vec2[x].end(),mid-dd)-vec2[x].begin();
	}
	return res-1;
}

int ask(int x,int k) {
	int res=0;
	for (int l=1,r=INF;l<=r;) {
		int mid=(l+r)>>1;
		if (check(x,mid)>=k) r=mid-1,res=mid;
		else l=mid+1;//,res=mid;
	}
	return res;
}

int main(void) {
	freopen("data.in","r",stdin);
	// freopen("myp.out","w",stdout);
	int n=read(),m=read();
	rep(i,2,n) {
		int x=read(),y=read(),w=read();
		add_edge(x,y,w);
	}
	dfs1(dep[1]=1); dfs2(1,1);
	root=0; mx[0]=INF; sum=n;
	get_root(1,0);
	del[root]=1;
	build(root);
	rep(i,1,n) change(i);
	rep(i,1,n) {
		std:: sort(vec1[i].begin(),vec1[i].end());
		std:: sort(vec2[i].begin(),vec2[i].end());
	}
	rep(i,1,n) printf("%d\n", ask(i,m));
	printf("%d\n", INF);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/85175429