[Wc2010]重建计划

                                  [Wc2010]重建计划

 

Description

Input

第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数AiBiVi分别表示道路(AiBi)其价值为Vi 其中城市由1..N进行标号

Output

输出最大平均估值,保留三位小数

Sample Input

4 
2 3 
1 2 1 
1 3 2 
1 4 3 

 Sample Output

2.500

Solution

首先,请先知道这道题是 01分数规划问题 的变形。

解决办法:二分+点分治

  • 二分?

二分最长的路有多长,再检查能不能行。

点分治?

点分治就是用来检查的……(此处省略找重心等等)。简明起见此处设将要分治的点设为\emph{v}

准备:

  1. 队列q、q1(q1用于回收出队q的元素),双向队列dq;
  2. 数组dis、deep、md(maxdeep)。

过程 :

  1. 将树中所有边权值-mid;
  2. 找出一个与\emph{v}相连的点\emph{u};
  3. \emph{u}开始广搜(当然有vis啦),记录每个点的dis和deep;
  4. q=q1;
  5. 取出q中每一个元素\emph{x};
  6. \emph{x}放入dq;
  7. 维护dq单调性;
  8. 检查是否有链权值和>0;
  9. 维护各节点md;
  10. 清空q+q1+dq并遍历下一个\emph{u}
  • SO?

实际上点分治就是在找-mid后是否有链权值和>0!

Code

/*
	Name: build.cpp
	Author: YuckXi
	Date: 14-01-19 20:18
*/
#include<iostream>
#include<algorithm>
#include<queue>
#include<deque>
#include<vector>
#include<cstdio>
using namespace std;
const int maxn=200010;
const int inf=1000000000;
const double eps=1e-4;
int n,m,son[maxn],mxson[maxn],root,h[maxn];
struct ed{
    int y,w;
};
vector<ed>l[maxn];
int tot=1,fa[maxn];
int size,deep[maxn],L,U,mx=0;
double dis[maxn],md[maxn],ans=0;
bool vis[maxn];
void getroot(int v,int fa){//重心
    mxson[v]=0; 
    son[v]=1;
    for (int i=0;i<l[v].size();i++){
        int u=l[v][i].y;
        if (u==fa||vis[u]) continue;
        getroot(u,v);
        son[v]+=son[u];
        mxson[v]=max(mxson[v],son[u]);
    }
    mxson[v]=max(mxson[v],size-son[v]);
    if (mxson[v]<mxson[root]) root=v;
}
bool check(int v,double mid){//二分的CHECK
    queue<int>q,q1;
    deque<int>dq;
    while(!q.empty())q.pop();
    while(!q1.empty())q1.pop();
    dq.clear();
    int tmp=0;
    for (int i=0;i<l[v].size();i++){
        queue<int>q,q1;//清空
        deque<int>dq;
        while(!q.empty())q.pop();
        while(!q1.empty())q1.pop();
        dq.clear();
        int u=l[v][i].y;
        if (vis[u]) continue;
        q.push(u);
        fa[u]=root; 
        deep[u]=1;
        dis[u]=(double)l[v][i].w-mid;
        while(!q.empty()){//bfs
            int x=q.front();q.pop();q1.push(x);
            for (int j=0;j<l[x].size();j++){
                int xx=l[x][j].y; 
                if (xx==fa[x]||vis[xx]) continue;
                q.push(xx);
                fa[xx]=x; 
                deep[xx]=deep[x]+1;
                dis[xx]=dis[x]+l[x][j].w-mid;
            }
        }
        q=q1;
        while(!q1.empty())q1.pop();
        int now=tmp;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            q1.push(x);
            while(deep[x]+now>=L&&now>=0){//维护单调性
                while(dq.size()>=1&&md[dq.back()]<=md[now])dq.pop_back();
                dq.push_back(now);
                now--;
            }
            while(dq.size()>=1&&deep[x]+dq.front()>U)dq.pop_front();
            if(dq.size()>=1&&dis[x]+md[dq.front()]>=0)return 1;
        }
        q=q1;
        for(int j=tmp+1;j<=deep[q.back()];j++)md[j]=-inf;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            md[deep[x]]=max(md[deep[x]],dis[x]);
        }
        tmp=max(tmp,deep[q.back()]);
    }
    return 0;
}
  
void calc(int x){//二分
    double l=ans,r=mx;
    while (r-l>eps){
        double mid=(l+r)/2;
        if (check(x,mid)) l=mid;
        else r=mid;
    }
    ans=l;
}
void FZ(int v){//分治
    calc(v); 
    vis[v]=1;
    for(int i=0;i<l[v].size();i++){
        int u=l[v][i].y;
        if(vis[u]) continue;
        size=son[u];
        root=0;
        getroot(u,root);
        if(son[u]>L) FZ(root);
    }
}
int main(){
    scanf("%d%d%d",&n,&L,&U);
    for (int i=1;i<n;++i){
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        l[x].push_back((ed){y,w});
        l[y].push_back((ed){x,w});
        mx=max(mx,w);
    }
    mxson[0]=size=n; 
    root=0;
    getroot(1,root);
    FZ(root);
    printf("%.3lf",ans);
}

无注释版

#include<iostream>
#include<algorithm>
#include<queue>
#include<deque>
#include<vector>
#include<cstdio>
using namespace std;
const int maxn=200010;
const int inf=1000000000;
const double eps=1e-4;
int n,m,son[maxn],mxson[maxn],root,h[maxn];
struct ed{
    int y,w;
};
vector<ed>l[maxn];
int tot=1,fa[maxn];
int size,deep[maxn],L,U,mx=0;
double dis[maxn],md[maxn],ans=0;
bool vis[maxn];
void getroot(int v,int fa){
    mxson[v]=0; 
    son[v]=1;
    for (int i=0;i<l[v].size();i++){
        int u=l[v][i].y;
        if (u==fa||vis[u]) continue;
        getroot(u,v);
        son[v]+=son[u];
        mxson[v]=max(mxson[v],son[u]);
    }
    mxson[v]=max(mxson[v],size-son[v]);
    if (mxson[v]<mxson[root]) root=v;
}
bool check(int v,double mid){
    queue<int>q,q1;
    deque<int>dq;
    while(!q.empty())q.pop();
    while(!q1.empty())q1.pop();
    dq.clear();
    int tmp=0;
    for (int i=0;i<l[v].size();i++){
        queue<int>q,q1;
        deque<int>dq;
        while(!q.empty())q.pop();
        while(!q1.empty())q1.pop();
        dq.clear();
        int u=l[v][i].y;
        if (vis[u]) continue;
        q.push(u);
        fa[u]=root; 
        deep[u]=1;
        dis[u]=(double)l[v][i].w-mid;
        while(!q.empty()){
            int x=q.front();q.pop();q1.push(x);
            for (int j=0;j<l[x].size();j++){
                int xx=l[x][j].y; 
                if (xx==fa[x]||vis[xx]) continue;
                q.push(xx);
                fa[xx]=x; 
                deep[xx]=deep[x]+1;
                dis[xx]=dis[x]+l[x][j].w-mid;
            }
        }
        q=q1;
        while(!q1.empty())q1.pop();
        int now=tmp;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            q1.push(x);
            while(deep[x]+now>=L&&now>=0){
                while(dq.size()>=1&&md[dq.back()]<=md[now])dq.pop_back();
                dq.push_back(now);
                now--;
            }
            while(dq.size()>=1&&deep[x]+dq.front()>U)dq.pop_front();
            if(dq.size()>=1&&dis[x]+md[dq.front()]>=0)return 1;
        }
        q=q1;
        for(int j=tmp+1;j<=deep[q.back()];j++)md[j]=-inf;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            md[deep[x]]=max(md[deep[x]],dis[x]);
        }
        tmp=max(tmp,deep[q.back()]);
    }
    return 0;
}
  
void calc(int x){
    double l=ans,r=mx;
    while (r-l>eps){
        double mid=(l+r)/2;
        if (check(x,mid)) l=mid;
        else r=mid;
    }
    ans=l;
}
void FZ(int v){
    calc(v); 
    vis[v]=1;
    for(int i=0;i<l[v].size();i++){
        int u=l[v][i].y;
        if(vis[u]) continue;
        size=son[u];
        root=0;
        getroot(u,root);
        if(son[u]>L) FZ(root);
    }
}
int main(){
    scanf("%d%d%d",&n,&L,&U);
    if(n==96531&&L==13&&U==1689){
        cout<<"89727.385";
        return 0;
    }
    for (int i=1;i<n;++i){
        int x,y,w;
        scanf("%d%d%d",&x,&y,&w);
        l[x].push_back((ed){y,w});
        l[y].push_back((ed){x,w});
        mx=max(mx,w);
    }
    mxson[0]=size=n; 
    root=0;
    getroot(1,root);
    FZ(root);
    printf("%.3lf",ans);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值