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

    dbzoj
    luogu

    sol

    点分治+二分答案+单调队列。
    点分,每次考虑所有过重心的路径,二分一个答案(mid),给每条边的边权减掉一个(mid)后,满足条件的路径应该是长度介于(L)(U)之间,且权值和大于等于(0)的。
    (bfs)一遍求出每个点到重心的路径的长度(dep)和路径权值(dis)。由于是(bfs),所以(dep)一定是单调增的。
    维护一个路径长度单调减而路径权值单调增的单调队列,由于待匹配路径的(dep)单调增,所以可以从大往小把原有路径加入单调队列,保证单调队列中的任意元素取出来和待匹配路径匹配都能满足大于等于(L)的条件。
    每次与队首计算贡献,注意要满足长度之和小于等于(U)的条件。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 1e5+5;
    const double eps = 1e-4;
    int n,L,U,to[N<<1],nxt[N<<1],ww[N<<1],head[N],cnt,Max;
    int sz[N],f[N],sum,root,vis[N],mark[N],Q[N],H,T,dep[N],q[N];
    double ans,dis[N],t[N];
    void link(int u,int v,int w)
    {
    	to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;
    	head[u]=cnt;
    }
    void getroot(int u,int fa)
    {
    	sz[u]=1;f[u]=0;
    	for (int e=head[u];e;e=nxt[e])
    		if (!vis[to[e]]&&to[e]!=fa)
    		{
    			getroot(to[e],u);
    			sz[u]+=sz[to[e]];
    			f[u]=max(f[u],sz[to[e]]);
    		}
    	f[u]=max(f[u],sum-sz[u]);
    	if (f[u]<f[root]) root=u;
    }
    void bfs(int u,double mid)
    {
    	Q[H=T=1]=u;mark[u]=1;
    	while (H<=T)
    	{
    		int u=Q[H++];
    		for (int e=head[u];e;e=nxt[e])
    			if (!vis[to[e]]&&!mark[to[e]])
    			{
    				dep[to[e]]=dep[u]+1,dis[to[e]]=dis[u]+(double)ww[e]-mid;
    				Q[++T]=to[e];mark[to[e]]=1;
    			}
    	}
    }
    bool check(int u,double mid)
    {
    	int fg=0,maxd=0;
    	for (int e=head[u];e;e=nxt[e])
    		if (!vis[to[e]])
    		{
    			dis[to[e]]=(double)ww[e]-mid;dep[to[e]]=1;
    			bfs(to[e],mid);
    			int hd=1,tl=0,j=maxd;
    			for (int i=1;i<=T;++i)
    			{
    				while (j>=0&&j+dep[Q[i]]>=L)
    				{
    					while (hd<=tl&&t[q[tl]]<t[j]) --tl;
    					q[++tl]=j;--j;
    				}
    				while (hd<=tl&&dep[Q[i]]+q[hd]>U) ++hd;
    				if (hd<=tl&&dis[Q[i]]+t[q[hd]]>=0) fg=1;
    			}
    			maxd=max(maxd,dep[Q[T]]);
    			for (int i=1;i<=T;++i)
    			{
    				mark[Q[i]]=0;
    				t[dep[Q[i]]]=max(t[dep[Q[i]]],dis[Q[i]]);
    			}
    		}
    	for (int i=1;i<=maxd;++i) t[i]=-1e12;
    	return fg;
    }
    void calc(int u)
    {
    	double l=ans,r=Max;
    	while (r-l>eps)
    	{
    		double mid=(l+r)/2;
    		if (check(u,mid)) l=mid;
    		else r=mid;
    	}
    	ans=l;
    }
    void solve(int u)
    {
    	vis[u]=1;calc(u);
    	for (int e=head[u];e;e=nxt[e])
    		if (!vis[to[e]])
    		{
    			sum=sz[to[e]];root=0;
    			getroot(to[e],0);
    			solve(root);
    		}
    }
    int main()
    {
    	n=gi();L=gi();U=gi();
    	for (int i=1;i<n;++i)
    	{
    		int u=gi(),v=gi(),w=gi();
    		link(u,v,w);link(v,u,w);Max=max(Max,w);
    	}
    	sum=f[0]=n;
    	getroot(1,0);
    	solve(root);
    	printf("%.3lf
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    使用NSTask调用shell
    《UML和模式应用》读书笔记(一)
    iOS网络编程
    多线程
    Quartz2D
    沙盒中的数据存取
    UIButton设置为圆形按钮并增加边框
    Mac开发快速入门
    JavaWeb学习总结(三)response与request
    JavaWeb学习总结(二) Servlet
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8706219.html
Copyright © 2011-2022 走看看