zoukankan      html  css  js  c++  java
  • [BZOJ]1758: [Wc2010]重建计划

    题目大意:给定一棵n个点的带边权的树和l,u,求长度在[l,u]之间平均权值最大的链的权值。(n<=100,000)

    思路:二分答案,把树上每条边减去二分出的答案,点分治check是否有长度在[l,u]之间权值和大等0的链,每次把每棵子树按深度排序,记下各个深度到根距离最大的节点,再用单调队列统计即可,总复杂度O(nlogn^2)。此题卡常差评,重心只要算一次,不用每次二分都算,稍微卡卡就过了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 100000
    struct edge{int nx,t,w;}e[MN*2+5];
    int n,a,b,h[MN+5],en,sz,ms,u[MN+5],s[MN+5],ht[MN+5],d[MN+5];
    struct que{int nx,t;}qu[MN+5];
    int qh[MN+5],qun,q[MN+5],qn,dq[MN+5],ql,qr,cnt,rt[MN+5];
    double w,dis[MN+5],mxd[MN+5];
    inline void ins(int x,int y,int w)
    {
        e[++en]=(edge){h[x],y,w};h[x]=en;
        e[++en]=(edge){h[y],x,w};h[y]=en;
    }
    void dfs(int x)
    {
        s[x]=ht[x]=u[x]=1;
        for(int i=h[x];i;i=e[i].nx)if(!u[e[i].t])
        {
            dis[e[i].t]=dis[x]+e[i].w-w;
            d[e[i].t]=d[x]+1;
            dfs(e[i].t);
            s[x]+=s[e[i].t];
            ht[x]=max(ht[x],ht[e[i].t]+1);
        }
        u[x]=0;
    }
    void getrt(int x)
    {
        int mx=0,i;u[x]=1;
        for(i=h[x];i;i=e[i].nx)if(!u[e[i].t])
            getrt(e[i].t),mx=max(mx,s[e[i].t]);
        mx=max(mx,sz-s[x]);
        if(mx<ms)ms=mx,rt[cnt]=x;
        u[x]=0;
    }
    bool solve(int x)
    {
        int i,k,l,p=0,o,mx=0;
        u[x]=1;
        for(i=h[x];i;i=e[i].nx)if(!u[e[i].t])
        {
            dis[e[i].t]=e[i].w-w;
            d[e[i].t]=1;
            dfs(e[i].t);
            mx=max(mx,ht[e[i].t]);
        }
        memset(qh,qun=0,sizeof(int)*(mx+1));
        for(i=h[x];i;i=e[i].nx)if(!u[e[i].t])
            qu[++qun]=(que){qh[ht[e[i].t]],e[i].t},qh[ht[e[i].t]]=qun;
        for(i=1;i<=mx;++i)
        {
            mxd[i]=-1e18;
            for(int&j=qh[i];j;p=i,j=qu[j].nx)
            {
                for(u[q[k=qn=ql=0]=qu[j].t]=1,qr=-1;k<=qn;++k)
                {
                    while(p>=0&&d[q[k]]+p>=a)
                    {
                        while(ql<=qr&&mxd[p]>=mxd[dq[qr]])--qr;
                        dq[++qr]=p--;
                    }
                    while(ql<=qr&&d[q[k]]+dq[ql]>b)++ql;
                    if(ql<=qr&&mxd[dq[ql]]+dis[q[k]]>=0)return true;
                    for(o=h[q[k]];o;o=e[o].nx)if(!u[e[o].t])u[q[++qn]=e[o].t]=1;
                }
                for(k=0;k<=qn;++k)mxd[d[q[k]]]=max(mxd[d[q[k]]],dis[q[k]]),u[q[k]]=0;
            }
        }
        for(i=h[x];i;i=e[i].nx)if(!u[e[i].t])
        {
            if(!rt[++cnt])sz=ms=s[e[i].t],getrt(e[i].t);
            if(solve(rt[cnt]))return true;
        }
        return false;
    }
    bool check(double x)
    {
        memset(u,cnt=0,sizeof(u));
        w=x;if(!rt[0])dfs(1),sz=ms=n,getrt(1);
        return solve(rt[0]);
    }
    int main()
    {
        int i,x,y;double l,r,mid;
        n=read();a=read();b=read();
        for(i=1;i<n;++i)x=read(),y=read(),ins(x,y,read());
        for(l=1,r=1000000;r-l>5*1e-4;)(check(mid=(l+r)/2)?l:r)=mid;
        printf("%.3lf",(l+r)/2);
    }
  • 相关阅读:
    about_并查集
    MST_prim
    MST_kruskal
    物联网的未来:关于物联网的10个预测
    如何展现云计算安全领导力
    虚拟机发展依然强劲,但会被容器取代吗?
    如何从人工智能部署中获取最大价值
    维特根斯坦:为何夸大人工智能是对人性的贬损?
    区块链技术还在不断创新
    区块链真正能用来干什么?这5件事说清楚了
  • 原文地址:https://www.cnblogs.com/ditoly/p/BZOJ1758.html
Copyright © 2011-2022 走看看