zoukankan      html  css  js  c++  java
  • [BZOJ1758/WC2010]重建计划

    Description

    Input
    第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数(A_i,B_i,V_i)分别表示道路((A_i,B_i)),其价值为(V_i) 其中城市由1..N进行标号

    Output
    输出最大平均估值,保留三位小数

    Sample Input
    4
    2 3
    1 2 1
    1 3 2
    1 4 3

    Sample Output
    2.500

    HINT
    (Nleqslant 100000,1leqslant Lleqslant Uleqslant N-1,V_ileqslant 1000000)


    考虑二分答案,然后把边权减去二分出的答案,判断是否存在>0的路径即可

    点分治合并路径的时候记得按秩合并,即将子树按最深深度排序后枚举,开一个单调队列,统计完一棵子树后累计答案

    二分有好几个位置,最外面、点分时、枚举子树时,放最外面常数最大(然而我就是这么写的),放在中间的位置可以随时改变二分上下界

    为了卡常,可以先把点分治的重心枚举顺序先弄出来,然后类似for循环去点分治(因为luogu单点时限,Bzoj不需要)

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)	putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e5;
    const double eps=1e-10,unit=1e-4;
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],val[(N<<1)+10];
    int size[N+10],Df[N+10],Root[N+10];
    bool vis[N+10],flag;
    double DV[N+10],Del;
    int root,Max,r_sz;
    int n,L,R,tot;
    void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
    void Get_root(int x,int fa,int sz){
    	int res=0; size[x]=1;
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    		if (son==fa||vis[son])	continue;
    		Get_root(son,x,sz);
    		size[x]+=size[son];
    		res=max(res,size[son]);
    	}
    	res=max(res,sz-size[x]);
    	if (res<Max)	Max=res,root=x;
    }
    void get_Df(int x,int fa,int deep){
    	Df[x]=deep;
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    		if (son==fa||vis[son])	continue;
    		get_Df(son,x,deep+1);
    		Df[x]=max(Df[x],Df[son]);
    	}
    }
    void get_dis(int x,int fa,double v,int Dp){
    	if (Dp>R)	return;
    	DV[Dp]=max(DV[Dp],v);
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    		if (son==fa||vis[son])	continue;
    		get_dis(son,x,v+val[p]-Del,Dp+1);
    	}
    }
    struct S1{
    	int x,Deep; double v;
    	oid insert(int _x,int _D,double _v){x=_x,Deep=_D,v=_v;}
    	bool operator <(const S1 &tis)const{return Deep<tis.Deep;}
    }A[N+10];
    double f[N+10];
    void solve(double *a,int &la,double *b,int &lb){
    	la=min(la,R),lb=min(lb,R);
    	static int h[N+10]; int head=1,tail=0;
    	for (int i=lb,j=0;i;i--){
    		while (j<=la&&i+j<=R){
    			while (head<=tail&&a[h[tail]]<=a[j])	tail--;
    			h[++tail]=j++;
    		}
    		while (head<=tail&&h[head]+i<L)	head++;
    		if (head>tail)	continue;
    		if (a[h[head]]+b[i]>-eps){
    			flag=1;
    			return;
    		}
    	}
    }
    void merge(double *a,int &la,double *b,int &lb){for (int i=1;i<=max(la,lb);i++)	a[i]=max(a[i],b[i]),b[i]=-inf; la=lb;}
    void divide(int len){
    	if (len>n)	return;
    	int x=Root[len];
    	if (flag)	return;
    	is[x]=1; int son_sz=0;//num of son
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    		if (vis[son])	continue;
    		get_Df(son,0,1),Df[son]=min(Df[son],R);
    		A[++son_sz].insert(son,Df[son],val[p]-Del);
    	}
    	int f_sz=0;
    	sort(A+1,A+1+son_sz);
    	if (A[son_sz].Deep<<1<L){
    		divide(len+1);
    		return;
    	}
    	for (int i=1;i<=son_sz;i++){
    		get_dis(A[i].x,0,A[i].v,1);
    		if (f_sz+A[i].Deep>=L){
    			solve(f,f_sz,DV,A[i].Deep);
    			if (flag)	return;
    		}
    		merge(f,f_sz,DV,A[i].Deep);
    	}
    	if (flag)	return;
    	for (int i=1;i<=f_sz;i++)	f[i]=-inf;
    	divide(len+1);
    }
    bool check(double v){
    	Del=v,flag=0;
    	memset(vis,0,sizeof(vis));
    	for (int i=1;i<=R;i++)	DV[i]=f[i]=-inf;
    	divide(1);
    	return flag;
    }
    void Frt(int x){//Find root
    	is[Root[++r_sz]=x]=1;
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    		if (vis[son])	continue;
    		root=0,Max=inf;
    		Get_root(son,0,size[son]);
    		Frt(root);
    	}
    	is[x]=0;
    }
    int main(){
    	n=read(),L=read(),R=read();
    	double l=1e9,r=0;
    	for (int i=1;i<n;i++){
    		int x=read(),y=read(),z=read();
    		insert(x,y,z);
    		l=min(l,1.0*z);
    		r=max(r,1.0*z);
    	}
    	root=0,Max=inf;
    	Get_root(1,0,n);
    	Frt(root);
    	while (l<=r){
    		double mid=(l+r)/2;
    		if (check(mid))	l=mid+unit;
    		else	r=mid-unit;
    	}
    	printf("%.3lf
    ",r);
    	return 0;
    }
    
  • 相关阅读:
    ruby中的特殊字符
    android and webview
    ActiveRecord::Base.establish_connection
    Ruby 创建目录
    不能手动输入或粘贴
    eclipse找不到 help>software update>find and install
    PL/SQL 创建、查看、操作用户
    XML文件
    javascript 获取页面高度(多种浏览器)(转)
    Eclipse to android
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10214917.html
Copyright © 2011-2022 走看看