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

    题目

    首先看到要让一个平均值最大,想到(0/1)分数规划

    二分一个(mid)作为答案

    如果存在

    [frac{sum_{ein S}v(e)}{sum_{i=1}^{|S|}1}>mid ]

    那么

    [sum_{ein S}v(e)-mid>0 ]

    也就是所有的边权减掉(mid)之后找出一条长度在([l,r])之间的大于(0)的路径

    我们点分治

    我们处理完当前分治重心的一棵子树后就把这棵子树的信息做成一个桶(g[i])就表示长度为(i)的路径中最长的路径

    之后我们和之前存储所有其他子树做一个合并

    发现如果当前的路径长度是(x),那么需要一条([l-x,r-x])的路径和这条路径搭配

    随着(x)减小,这个抉择区间向后移动,但是区间总长始终不变,于是这不就是一个滑动窗口吗

    用一个单调队列维护一下就好了

    复杂度(O(nlog^2n))

    但是容易被卡掉的一点是每次用单调队列扫一遍的复杂度取决于之前访问过的子树的最长路径

    扫把树随便就卡成(O(n^2log^2n))

    于是需要按照最大深度从小到大访问子树,就能保证复杂度了

    卡常严重,需要提前预处理好一些东西

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define maxn 100010
    #define re register
    #define eps 1e-4
    #define inf 99999999
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct son{int A,B;}st[maxn];
    struct E{int v,nxt;double w;}e[maxn<<1];
    int X[maxn],Y[maxn],V[maxn],head[maxn],sum[maxn],mx[maxn],vis[maxn],t[maxn],q[maxn];
    double d[maxn],g[maxn],h[maxn];
    int n,S,num,m,tot,now,rt,l,r,md,L,mt;
    std::vector<int> v[maxn],u[maxn];
    double ans;
    inline int cmp(son a,son b) {return a.A<b.A;}
    inline void add(int x,int y,double z) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;}
    void getroot(int x,int fa) {
    	sum[x]=1,mx[x]=0;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(e[i].v==fa||vis[e[i].v]) continue;
    		getroot(e[i].v,x);
    		sum[x]+=sum[e[i].v];mx[x]=max(mx[x],sum[e[i].v]);
    	}
    	mx[x]=max(mx[x],S-sum[x]);
    	if(mx[x]<now) now=mx[x],rt=x;
    }
    void getdis(int x,int fa,double len,int sz) {
    	d[++tot]=len,t[tot]=sz;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(e[i].v==fa||vis[e[i].v]) continue;
    		getdis(e[i].v,x,len+e[i].w,sz+1);
    	}
    }
    void getmdep(int x,int fa,int sz) {
    	if(sz>mt) mt=sz;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(e[i].v==fa||vis[e[i].v]) continue;
    		getmdep(e[i].v,x,sz+1);
    	}
    }
    void find(int x) {
    	vis[x]=1;int top=0;
    	for(re int i=head[x];i;i=e[i].nxt) {
    		if(vis[e[i].v]) continue;
    		mt=0;getmdep(e[i].v,0,1);st[++top].A=mt,st[top].B=i;
    	}
    	std::sort(st+1,st+top+1,cmp);
    	for(re int i=1;i<=top;i++) v[x].push_back(st[i].B);
    	for(re int k=0;k<v[x].size();k++) {
    		re int i=v[x][k];
    		if(vis[e[i].v]) continue;
    		S=sum[e[i].v],now=inf,getroot(e[i].v,0),u[x].push_back(rt),find(rt);
    	}
    }
    void dfs(int x) {
    	vis[x]=1;int cur=0,top=0;mt=0;
    	for(re int k=0;k<v[x].size();k++) {
    		re int i=v[x][k];
    		if(vis[e[i].v]) continue;
    		md=0;tot=0;cur++;getdis(e[i].v,0,e[i].w,1);
    		for(re int j=1;j<=tot;j++) {
    			g[t[j]]=max(g[t[j]],d[j]);md=max(md,t[j]);
    			if(t[j]>=l&&t[j]<=r) ans=max(ans,d[j]);
    		}
    		if(cur==1) {
    			mt=max(mt,md);
    			for(re int j=1;j<=md;j++) h[j]=g[j];
    			for(re int j=1;j<=tot;j++) g[t[j]]=-inf;
    			continue;
    		}
    		int head=1,tail=0,U=min(r-md,mt);
    		for(re int j=max(1,l-md);j<=U;j++) {
    			while(head<=tail&&h[j]>h[q[tail]]) tail--;
    			q[++tail]=j;
    		}
    		if(head<=tail) ans=max(ans,g[md]+h[q[head]]);
    		int lp=l-md,rp=r-md;
    		for(re int j=md-1;j>=1;j--) {
    			rp++,lp++;
    			while(head<=tail&&h[rp]>h[q[tail]]) tail--;
    			q[++tail]=rp;
    			while(head<=tail&&q[head]<lp) head++;
    			if(head<=tail) ans=max(ans,g[j]+h[q[head]]);
    		}
    		mt=max(mt,md);
    		for(re int j=1;j<=md;j++) h[j]=max(h[j],g[j]);
    		for(re int j=1;j<=md;j++) g[j]=-inf;
    	}
    	for(re int i=1;i<=mt;i++) h[i]=-inf;
    	for(re int k=0;k<v[x].size();k++) {
    		re int i=v[x][k];
    		if(vis[e[i].v]) continue;
    		dfs(u[x][k]);
    	}
    }
    inline int check(double mid) {
    	num=0;memset(head,0,sizeof(head));memset(vis,0,sizeof(vis));
    	for(re int i=1;i<n;i++) 
    		add(X[i],Y[i],double(V[i])-mid),add(Y[i],X[i],double(V[i])-mid);
    	S=n,now=inf,ans=-inf,getroot(1,0);
    	dfs(rt);
    	return ans>0;
    }
    int main() {
    	n=read(),l=read(),r=read();
    	for(re int i=1;i<n;i++) X[i]=read(),Y[i]=read(),V[i]=read();
    	double L=0,R=900000.0; 
    	memset(h,-20,sizeof(h));memset(g,-20,sizeof(g));
    	for(re int i=1;i<n;i++) add(X[i],Y[i],0),add(Y[i],X[i],0);
    	S=n,now=inf,ans=-inf,getroot(1,0);find(rt);
    	while(R-L>eps) {
    		double mid=(L+R)/2.0;
    		if(check(mid)) L=mid;else R=mid;
    	}
    	printf("%.3lf
    ",L);
    	return 0;
    }
    
  • 相关阅读:
    数据挖掘:基本概念理解
    Linux:数据库服务(Mysql安装及链接、远程链接、genelog)
    Linux:WebServer(Nginx 虚拟主机配置与伪静态实现)
    Linux:WebServer(Apacge)
    单例和多线程
    Redis注册成服务
    Redis基础学习
    sqlserver查询使用with(nolock)详解
    JAVA设计模式-策略模式
    JAVA设计模式-代理模式
  • 原文地址:https://www.cnblogs.com/asuldb/p/10422515.html
Copyright © 2011-2022 走看看