Lady CA and the graph(HDU-5664)

题目描述:

Lady CA has a tree with n points numbered 1,2,...,n, and each edge has its weight. The unique route connecting two points is called a chain, and the length of a chain equals the sum value of the weights of the edges passed.

The point number m is called the root. Lady CA defines a special kind of chain called folded chain, the chain connecting the points numbered x,y(x≠y) is called a folded chain, if and only if the chain connecting the point numbered x and the root doesn't pass the point numbered y, and the chain connecting the point numbered y and the root doesn't pass the point numbered x.

Lady CA wants to find the length of the kth longest folded chain. Notice that the chain connecting the points numbered x,y and the chain connecting the points numbered y,x are the same.

输入

The first line contains an integer T(1≤T≤3)——The number of the test cases. For each test case:
The first line contains three integers n(2≤n≤50,000),m(1≤m≤n),k(1≤k≤n×(n−1)2). Between each two adjacent integers there is a white space separated.
The second line to the nth line describes the n−1 edges in the graph. Each line contains three integers u,v(1≤u,v≤n,u≠v),w(1≤w≤10,000), which means there is an edge which has a weight w connecting the points numbered u,v. Between each two adjacent integers there is a white space separated.

输出

For each test case, the only line contains the only integer that is the length of the kth longest folded chain. If the kth longest folded chain doesn't exist, print NO.

样例输入

思路:

做这题首先需要知道的思想就是:求一个第k大的值能够转化为二分答案求最大的不小于它的数大于等于k个的值(这话有点绕但十分重要),它打开我们解这道题的一个通道。

接下来就是求树中大于等于这个值的路径数了,这个自然能想到点分治求解,做法和之前我写的一道题一样(POJ-1741),但是接下来就要考虑到限制条件了,就是路径的两端都不能是另一端的祖先,同样要将其在答案中减去。那么就只要深搜扫一遍树,对于每个节点,算出祖先中距离自己大于当前二分值的祖先个数即可。至于如何快速计算这个数,用一个树状数组即可,下标存长度,不过数组开不下,那么就先把树扫一遍,记下每个长度,再将其离散化即可

还有一个要注意的就是由于要二分答案,不能每次都把点分治的操作一模一样地做一遍,所以就把它给预处理出来,包括操作顺序,以及每个重心后的子树的重心等,还有每个点到重心的距离,存在两个vector里,这样就能直接访问了!

综合以上的思路,最终便能求解,复杂度约为nlog3n,代码有点长,要耐心打,仔细调

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define FOR(i,l,r) for(int i=(int)l;i<=(int)r;i++)
#define DOR(i,r,l) for(int i=(int)r;i>=(int)l;i--)
#define loop(i,n) for(int i=0;i<(int)n;i++)
#define ll long long
#define sf scanf
#define pf printf
#define mms(a,x) memset(a,x,sizeof a)
#define lowbit(x) (x)&-(x)
using namespace std;
const int N=50005;
int n,m;ll k;
struct Graph{
	int tot,to[N<<1],nxt[N<<1],len[N<<1],head[N];
	void add(int x,int y,int z){tot++;to[tot]=y;len[tot]=z;nxt[tot]=head[x];head[x]=tot;}
	void clear(){mms(head,-1),tot=0;}
	#define EOR(i,x) for(int i=G.head[x];i!=-1;i=G.nxt[i])
}G;
vector<int>v[N*10],rt_v[N];

bool vis[N];
int RT,dfn,center,t_sz,sz[N],mx[N];
void get_center(int x,int f){
	sz[x]=1,mx[x]=0;
	EOR(i,x){
		int v=G.to[i];
		if(v==f||vis[v])continue;
		get_center(v,x);
		sz[x]+=sz[v];
		mx[x]=max(mx[x],sz[v]);
	}
	mx[x]=max(mx[x],t_sz-sz[x]);
	if(!center||mx[center]>mx[x])center=x;
}
void dis_init(int x,int f,int dis){
	v[dfn].push_back(dis);
	EOR(i,x){
		int v=G.to[i];
		if(v==f||vis[v])continue;
		dis_init(v,x,dis+G.len[i]);
	}
}
void son_init(int x,int f,int dis){
	dfn++;
	dis_init(x,f,dis);
	sort(v[dfn].begin(),v[dfn].end());
}
void dfs_init(int x){
	vis[x]=1;
	son_init(x,0,0);
	EOR(i,x){
		int v=G.to[i];
		if(vis[v])continue;
		son_init(v,x,G.len[i]);
		center=0,t_sz=sz[v];
		get_center(v,x);
		rt_v[x].push_back(center);
		dfs_init(center);
	}
}
void tree_init(){
	FOR(i,1,n)rt_v[i].clear();
	FOR(i,1,10*n)v[i].clear();
	mms(vis,0);
	dfn=0;
	center=0,t_sz=n;
	get_center(1,0);
	RT=center;
	dfs_init(center);
}

int id,sum,arr[N<<1];
struct Binary_Indexed_Tree{
	int c[N<<1];
	void update(int x,int val){while(x<=arr[0])c[x]+=val,x+=lowbit(x);}
	int sum(int x){int ret=0;while(x){ret+=c[x];x-=lowbit(x);}return ret;}
	void clear(){mms(c,0);}
}Tr;
int calc(int val){
	int ret=0,j=v[++id].size()-1,i=0;
	while(i<j){
		while(i<j&&v[id][i]+v[id][j]<val)i++;
		ret+=j-i,j--;
	}
	return ret;
}
void dfs(int x,int val){
	sum+=calc(val);
	loop(i,rt_v[x].size()){
		int v=rt_v[x][i];
		sum-=calc(val);
		dfs(v,val);
	}
}
void dis_dfs(int x,int f,int dis,int val){
	arr[++arr[0]]=dis,arr[++arr[0]]=dis-val;
	EOR(i,x){
		int v=G.to[i];
		if(v==f)continue;
		dis_dfs(v,x,dis+G.len[i],val);
	}
}
void update_dfs(int x,int f,int dis,int val){
	int pos1=lower_bound(arr+1,arr+arr[0]+1,dis)-arr;
	int pos2=lower_bound(arr+1,arr+arr[0]+1,dis-val)-arr;
	sum-=Tr.sum(pos2),Tr.update(pos1,1);
	EOR(i,x){
		int v=G.to[i];
		if(v==f)continue;
		update_dfs(v,x,dis+G.len[i],val);
	}
	Tr.update(pos1,-1);
}
int check(int x){
	sum=0,dfs(RT,x);
	id=arr[0]=0,dis_dfs(m,0,0,x);
	sort(arr+1,arr+arr[0]+1);
	arr[0]=unique(arr+1,arr+arr[0]+1)-arr-1;
	update_dfs(m,0,0,x);
	return sum;
}
void init(){
	G.clear();
}
int main(){
	int T;
	sf("%d",&T);
	while(T--){
		int Mx=0;
		init();
		sf("%d%d%lld",&n,&m,&k);
		FOR(i,1,n-1){
			int x,y,z;
			sf("%d%d%d",&x,&y,&z);
			G.add(x,y,z),G.add(y,x,z);
			Mx=max(Mx,z);
		}
		tree_init();
		int l=0,r=n*Mx,ans=-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(check(mid)>=k)ans=mid,l=mid+1;
			else r=mid-1;
		}
		if(ans!=-1)pf("%d\n",ans);
		else puts("NO");
	}
	return 0;
}
posted @ 2019-03-01 21:31  Hëinz  阅读(195)  评论(0编辑  收藏  举报