• 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
    ",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)
    ",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
    ",l);
    
    	// C=1.5;
    	// solve(tmp);
    	// printf("%d
    ",ok);
    }
    
    
  • 相关阅读:
    LeetCode 50: Pow(x, n)
    Codility 1: equilibrium
    LeetCode 49: Anagrams
    crackme160--(5)
    crackme160--(4)
    魔兽显血改键工具的脱壳和修改
    crackme160--(3)
    crackme160--(1)
    python-装饰器
    编程语言C++01-C++入门学习路线
  • 原文地址:https://www.cnblogs.com/suika/p/10092952.html
Copyright © 2020-2023  润新知