Bzoj:1758:[Wc2010]重建计划:树的点分治

4 篇文章 0 订阅

题目链接:[Wc2010]重建计划

纯粹是为了复习板子,也没有什么思考,感觉是糟蹋了这道题了……

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=200010;
const int inf=1000000000;
const double eps=1e-4;
int n,m,s[maxn],dp[maxn],root,h[maxn];
struct edge{int to,next,w;}G[maxn*2];
int tot=1,fa[maxn],q[maxn],dq[maxn];
int size,deep[maxn],L,U,mx=0;
double dis[maxn],md[maxn],ans=0;
bool flag[maxn];

void add(int x,int y,int z){
	G[++tot].to=y;G[tot].next=h[x];h[x]=tot;G[tot].w=z;
	G[++tot].to=x;G[tot].next=h[y];h[y]=tot;G[tot].w=z;
}

void getroot(int x,int fa){
	dp[x]=0; s[x]=1;
	for (int i=h[x];i;i=G[i].next){
		int v=G[i].to;
		if (v==fa||flag[v]) continue;
		getroot(v,x); s[x]+=s[v];
		dp[x]=max(dp[x],s[v]);
	}dp[x]=max(dp[x],size-s[x]);
	if (dp[x]<dp[root]) root=x;
}

bool check(int rt,double mid){
	int tmp=0;
	for (int i=h[rt];i;i=G[i].next){
		int v=G[i].to;
		if (flag[v]) continue;
		q[0]=v; int head=0,t=1;
		fa[v]=root; deep[v]=1;
		dis[v]=(double)G[i].w-mid;
		while (head!=t){
			int u=q[head]; head++;
			for (int j=h[u];j;j=G[j].next){
				int x=G[j].to; 
				if (x==fa[u]||flag[x]) continue;
				q[t]=x; fa[x]=u; deep[x]=deep[u]+1;
				dis[x]=dis[u]+G[j].w-mid; t++;
			}
		}
		int l=1,r=0,now=tmp;
		for (int j=0;j<t;++j){
			int x=q[j];
			while (deep[x]+now>=L&&now>=0){
				while (l<=r&&md[dq[r]]<=md[now]) r--;
				dq[++r]=now; now--;
			}
			while (l<=r&&deep[x]+dq[l]>U) l++;
			if (l<=r&&dis[x]+md[dq[l]]>=0) return 1;
		}
		for (int j=tmp+1;j<=deep[q[t-1]];++j) md[j]=-inf;
		for (int j=0;j<t;++j){
			int x=q[j];
			md[deep[x]]=max(md[deep[x]],dis[x]);
		}
		tmp=max(tmp,deep[q[t-1]]);
	}return 0;
}

void calc(int x){
	double l=ans,r=mx;
	while (r-l>eps){
		double mid=(l+r)/2;
		if (check(x,mid)) l=mid;
		else r=mid;
	}ans=l;
}

void work(int x){
	calc(x); flag[x]=1;
	for (int i=h[x];i;i=G[i].next){
		int v=G[i].to;
		if (flag[v]) continue;
		size=s[v];
		getroot(v,root=0);
		if (s[v]>L) work(root);
	}
}

int main(){
	scanf("%d%d%d",&n,&L,&U);
	for (int i=1;i<n;++i){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z); mx=max(mx,z);
	}
	dp[0]=size=n; getroot(1,root=0);
	work(root);
	printf("%.3lf",ans);
}


  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值