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;
    }
    
  • 相关阅读:
    LeetCode Binary Tree Inorder Traversal
    LeetCode Populating Next Right Pointers in Each Node
    LeetCode Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode Reverse Linked List II
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Pascal's Triangle
    Palindrome Construct Binary Tree from Preorder and Inorder Traversal
    Pascal's Triangle II
    LeetCode Word Ladder
    LeetCode Binary Tree Zigzag Level Order Traversal
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10214917.html
Copyright © 2011-2022 走看看