• 【洛谷4292】[WC2010] 重建计划(分数规划+点分治)


    点此看题面

    • 给定一棵(n)个点的树,每条边有一个边权。
    • 要求找到一条边数在([L,U])范围内的路径,使得边权平均值最大。
    • (nle10^5)

    分数规划

    这种求平均值的问题显然就分数规划啊。

    考虑二分一个平均值(mid),然后给所有边权减去(mid)

    现在就是要求是否存在一条边数在([L,U])范围内的路径,使得边权和大于等于(0)

    点分治+单调队列

    总体而言还是比较套路的,对于每个点存下从它向每个子树里的路径。

    这种一个取值范围的问题显然只要开个桶维护每种深度的最大值,然后用单调队列即可维护。

    但要注意一个细节,就是我们在每个子树上花费的复杂度,不仅是它的深度,还有之前已处理过的子树的最大深度,所以我们需要把所有子树按最大深度排序之后再依次处理。

    还有就是这题比较卡常,因为树的形态不变,所以我们每次点分治找到分治重心不变,可以预先存下来建出点分树。

    代码:(O(nlog^2n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define DB double
    #define eps 1e-4
    #define add(x,y,z) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].v=z)
    #define nadd(x,y) (ne[++nee].nxt=nlnk[x],ne[nlnk[x]=nee].to=y)
    using namespace std;
    int n,L,U;int ee,lnk[N+5];struct edge {int to,nxt,v;}e[N<<1];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	char oc,FI[FS],*FA=FI,*FB=FI;
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }using namespace FastIO;
    namespace T//点分治
    {
    	DB mid,ev[N+5],u[N+5],v[N+5];int Rt,pd[N+5],nee,nlnk[N+5];edge ne[N+5];
    	int md[N+5];I bool cmp(CI x,CI y) {return md[x]<md[y];}
    	int rt,Sz[N+5],Mx[N+5],ud[N+5];I void GetRt(CI x,CI lst,RI sz)//找重心
    	{
    		Sz[x]=1,Mx[x]=0;for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&
    			!ud[e[i].to]&&(GetRt(e[i].to,x,sz),Sz[x]+=Sz[e[i].to],Mx[x]=max(Mx[x],Sz[e[i].to]));
    		(Mx[x]=max(Mx[x],sz-Sz[x]))<Mx[rt]&&(rt=x);
    	}
    	I void GD(CI x,CI id,CI lst=0,CI d=1) {md[id]=max(md[id],d);//求最大深度
    		for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&!ud[e[i].to]&&(GD(e[i].to,id,x,d+1),0);}
    	vector<int> s[N+5];I void Build(RI x)//建点分树
    	{
    		RI i,j,t=0;for(ud[x]=1,i=lnk[x];i;i=e[i].nxt) !ud[e[i].to]&&(GD(e[i].to,e[i].to),
    			s[x].push_back(e[i].to),rt=0,GetRt(e[i].to,x,Sz[e[i].to]),nadd(x,rt),Build(rt),0);//向下一分治重心连边
    		sort(s[x].begin(),s[x].end(),cmp);//把子节点按最大深度排序
    	}
    	I void dfs(CI x,DB g=0,CI lst=0,CI d=1) {v[d]=max(v[d],g);//记录每种深度的最大值
    		for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&!pd[e[i].to]&&(dfs(e[i].to,g+e[i].v-mid,x,d+1),0);}
    	int q[N+5];I bool Check(RI x)//检验答案
    	{
    		RI i;vector<int>::iterator it;if(pd[x]=1,s[x].empty()) return 0;//如果子树内没有其他点直接结束
    		for(i=lnk[x];i;i=e[i].nxt) ev[e[i].to]=e[i].v;for(i=1;i<=md[*--s[x].end()];++i) u[i]=-1e9;//初始化
    		RI H,T,mx=0;for(it=s[x].begin();it!=s[x].end();mx=md[*it],++it)//按深度从小到大枚举子节点
    		{
    			for(i=1;i<=md[*it];++i) v[i]=-1e9;dfs(*it,ev[*it]-mid);//清空后dfs
    			for(H=1,T=0,i=min(mx,U);i>=L;q[++T]=i--) W(H<=T&&u[q[T]]<=u[i]) --T;//用之前子树的信息初始化单调队列
    			for(i=1;i<=min(md[*it],U);++i)//枚举当前子树内的深度
    			{
    				if(H<=T&&i+q[H]>U&&++H,i<=L&&L-i<=mx) {W(H<=T&&u[q[T]]<=u[L-i]) --T;q[++T]=L-i;}//弹出队首不合法元素,加入队尾新元素
    				if(H<=T&&v[i]+u[q[H]]>=0) return 1;//检验
    			}
    			for(i=1;i<=md[*it];++i) u[i]=max(u[i],v[i]);//更新总信息
    		}
    		for(i=nlnk[x];i;i=ne[i].nxt) if(Check(ne[i].to)) return 1;return 0;//递归子树中的分治重心
    	}
    }
    int main()
    {
    	RI i,x,y,z;for(read(n,L,U),i=1;i^n;++i) read(x,y,z),add(x,y,z),add(y,x,z);
    	T::Mx[0]=1e9,T::GetRt(1,0,n),T::Build(T::Rt=T::rt);DB l=0,r=1e6;//初始建点分树预处理
    	W(r-l>eps) {for(i=1;i<=n;++i) T::pd[i]=0;//分数规划
    		T::mid=(l+r)/2,T::Check(T::Rt)?l=T::mid:r=T::mid;}return printf("%.3lf
    ",r),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Java接口自动化测试实战001----get、post方法实现与封装
    临近年关,两个磁盘占满引起的服务下线
    Abp小试牛刀之 图片上传
    Abp vNext异常处理的缺陷/改造方案
    Oh my God, Swagger API文档竟然可以这样写?
    【C#】DockPanelSuite 中 DockState.Document 状态下子窗体控件不显示的解决方案
    环境系列——cygwin启动flink
    环境系列——window10环境下编译Flink源码编译
    弱肉强食——《哆啦A梦:大雄的新恐龙》观后感
    bilibili插件推荐
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu4292.html
Copyright © 2020-2023  润新知