BZOJ1758: [Wc2010]重建计划

BZOJ1758: [Wc2010]重建计划

https://lydsy.com/JudgeOnline/problem.php?id=1758

分析:

  • 首先\(01\)分数规划,转化为求长度在\([L,U]\)的最长路。
  • 点分治,每层求某深度下的最大\(dis\)
  • 这里有一个操作,按子树深度最大值从小往大排序,这样保证之前操作部分的深度是可以枚举的,这个时间不会超过接下来遍历子树的时间。
  • 单调队列优化即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
#define N 100050
#define db(x) cerr<<#x<<" = "<<x<<endl
typedef long long ll;
typedef double f2;
int n,L,U,siz[N],f[N],used[N],tot,Q[N],fa[N],dep[N],a[N],la,root;
f2 C,dis[N],g[N];
int ok,mx[N];
char buf[100000],*p1,*p2;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int rd() {
	int x=0,f=1; char s=nc();
	while(s<'0'||s>'9') {if(s=='-') f=-1; s=nc();}
	while(s>='0'&&s<='9') x=(((x<<2)+x)<<1)+s-'0',s=nc();
	return f*x;
}
struct A {
	int to,val;
	A() {}
	A(int x_,int y_) {to=x_, val=y_;}
};
vector<A>v1[N],v2[N];
void get_root(int x,int y) {
	int i,lim=v1[x].size();
	siz[x]=1; f[x]=0;
	for(i=0;i<lim;i++) {
		int t=v1[x][i].to;
		if(t!=y&&!used[t]) {
			get_root(t,x);
			siz[x]+=siz[t];
			f[x]=max(f[x],siz[t]);
		}
	}
	f[x]=max(f[x],tot-siz[x]);
	if(f[x]<f[root]) root=x;
}
void get_dep(int x,int y) {
	int i,lim=v1[x].size();
	mx[x]=1; siz[x]=1;
	for(i=0;i<lim;i++) {
		int t=v1[x][i].to;
		if(t!=y&&!used[t]) {
			get_dep(t,x);
			mx[x]=max(mx[x],mx[t]+1);
			siz[x]+=siz[t];
		}
	}
}
inline bool cmp(const A &x,const A &y) {
	return mx[x.to]<mx[y.to];
}
void get_tree(int x) {
	used[x]=1;
	int i,lim=v1[x].size();
	get_dep(x,0);
	sort(v1[x].begin(),v1[x].end(),cmp);
	for(i=0;i<lim;i++) {
		int t=v1[x][i].to;
		if(!used[t]) {
			root=0;
			tot=siz[t];
			get_root(t,x);
			v2[x].push_back(A(root,0));
			get_tree(root);
		}
	}
}
int nowmx;
int bfs(int s) {
	int l=0,r=0,i;
	Q[r++]=s; dep[s]=1; nowmx=max(nowmx,1);
	while(l<r) {
		int x=Q[l++],lim=v1[x].size();
		for(i=0;i<lim;i++) {
			int t=v1[x][i].to;
			if(t!=fa[x]&&used[t]!=tot) {
				dep[t]=dep[x]+1;
				fa[t]=x;
				dis[t]=dis[x]+v1[x][i].val-C;
				nowmx=max(nowmx,dep[t]);
				Q[r++]=t;
			}
		}
	}
	return r;
}
int q[N];
void solve(int x) {
	int i,lim1=v1[x].size(),lim2=v2[x].size(),j,k;
	nowmx=0;
	used[x]=tot;
	g[0]=0;
	la=0;
	a[++la]=x;
	for(i=0;i<lim1;i++) {
		int t=v1[x][i].to,l=0,r=0;
		if(used[t]==tot) continue;
		fa[t]=x;
		dis[t]=v1[x][i].val-C;
		int lstmx=nowmx;
		int len=bfs(t);
		// db(t);
		// db(nowmx);
		// db(len);
		int m=min(U-1,lstmx);
		for(j=m;j>=(L-1)&&j>=0;j--) {
			while(l<r&&g[j]>=g[q[r-1]]) r--;
			q[r++]=j;
		}
		for(j=0;j<len;j++) a[++la]=Q[j];
		for(j=0;j<len;j++) {
			int p=Q[j];
			//[L-dep[p],U-dep[p]]
			
			if(l==r||L-dep[p]<q[r-1]) {
				for(k=r?(q[r-1]-1):m;k>=0&&k>=L-dep[p];k--) {
					while(l<r&&g[k]>=g[q[r-1]]) r--;
					q[r++]=k;
				}
			}
			while(l<r&&q[l]>U-dep[p]) l++;
			if(l<r) {
				if(dis[p]+g[q[l]]>0||abs(dis[p]+g[q[l]])<1e-8) {
					ok=1;
				}
			}
		}
		for(j=0;j<len;j++) {
			g[dep[Q[j]]]=max(g[dep[Q[j]]],dis[Q[j]]);
		}
		// db(g[1]);
		// db(g[2]);
	}
	for(i=1;i<=la;i++) {
		g[dep[a[i]]]=-1e10;
	}
	if(ok) return ;
	// return ;
	for(i=0;i<lim2;i++) {
		if(siz[v2[x][i].to]>=L)
		solve(v2[x][i].to);
	}
}
void dfs(int x) {
	int i,lim=v2[x].size();
	for(i=0;i<lim;i++) {
		printf("%d -> %d\n",x,v2[x][i].to);
		dfs(v2[x][i].to);
	}
}
int main() {
	n=rd(); L=rd(); U=rd();
	int i,x,y,z,mxx=0,mnn=1<<30;
	for(i=1;i<=n;i++) g[i]=-1e10;
	for(i=1;i<n;i++) {
		x=rd(); y=rd(); z=rd();
		v1[x].push_back(A(y,z));
		v1[y].push_back(A(x,z));
		mxx=max(mxx,z);
		mnn=min(mnn,z);
	}
	f[0]=1<<30;
	tot=n;
	get_root(1,0);
	int tmp=root;
	get_tree(root);
	f2 l=mnn,r=mxx;

	// dfs(tmp); return 0;
	// for(x=1;x<=n;x++) {
	// 	int lim=v1[x].size();
	// 	for(i=0;i<lim;i++) {
	// 		printf("%d -> %d(%d)\n",x,v1[x][i].to,v1[x][i].val);
	// 	}
	// }

	tot=2;
	while((r-l)>1e-4) {
		f2 mid=(l+r)/2;
		C=mid; ok=0;
		tot++;
		solve(tmp);
		if(ok) l=mid;
		else r=mid;
	}
	printf("%.3f\n",l);

	// C=1.5;
	// solve(tmp);
	// printf("%d\n",ok);
}

posted @ 2018-12-09 20:15  fcwww  阅读(153)  评论(0编辑  收藏  举报