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

    来自FallDream的博客,未经允许,请勿转载,谢谢。

    ------------------------------------------------------------------------------------------------

    题意:给定一棵n个点树,有边权,你要选出一条长度在[li,ri]之间的链,使得这条链上的边权和比去边的数量最大。  $ n<=10^{5}$

    题解:考虑二分答案,并且把所有边都减去那个值,原题转换为求是否有一条满足长度限制的链的边权和大等于0。

    这个很显然可以点分治,对于每一个子树,我们只需要前面子树的点在不同深度(也就是长度)的最大值就好了。我们改为用bfs取出子树的所有点,这样子点的深度连续,可以和别的子树连接的区间也是连续的,然后我们用一个单调队列维护前面子树的不同深度的最大值单调下降就可以啦。复杂度$nlog^{2}n$

    ------------------------------------------------------------------------------------------------

    然后这道题是怎么做到在几秒内a掉的?我一开始T了后来把每次的根都记下来才卡过去,大概要三十三秒....

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define MN 200000
    #define INF 1000000000LL
    #define eps 1e-4
    using namespace std;
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    double d[MN+5],w[MN+5];
    double mid;
    vector<int> v[MN+5];
    int maxdep,dep[MN+5],size[MN+5],q[MN+5],top=0,mark[MN+5];
    int n,low,up,minn,rt,tot,bigrt,cnt=0,head[MN+5],mx[MN+5],rtnum=0;
    int root[MN+5];
    struct edge{int to,next;double w;}e[MN*2+5];
    bool yes,b[MN+5];
    struct Queue{
        int hd,tl,n,qx[MN+5];
        void init(int size){hd=-1;tl=0;n=size;}
        void ins(int x)
        {
            if(hd>=tl&&qx[hd]<=x)return;
            if(hd<tl&&x>n)return;
            while(d[x]>=d[qx[hd]]&&hd>=tl) hd--;
            qx[++hd]=x;
        }
        double query(int x)
        {
            while(qx[tl]>x&&hd>=tl)++tl;
            if(hd<tl)return -INF;
            return d[qx[tl]];    
        }
    }Q;
    
    void ins(int f,int t,int w)
    {
        e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
        e[++cnt]=(edge){f,head[t],w};head[t]=cnt;
    }
    
    void getrt(int x,int fa)
    {
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa&&!b[e[i].to]) 
                getrt(e[i].to,x);
        if(max(tot-size[x],size[mx[x]])<minn) {minn=max(tot-size[x],size[mx[x]]);rt=x;}
    }
    
    void bfs(int x,int from)
    {
        int i,j;mark[x]=from;
        for(q[i=top=1]=x;i<=top;i++)
            for(int j=head[q[i]];j;j=e[j].next)
                if(!b[e[j].to]&&mark[e[j].to]!=from)
                    mark[q[++top]=e[j].to]=from;
    }
    
    void dfs(int x,int fa)
    {
        maxdep=max(maxdep,dep[x]); 
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa&&!b[e[i].to]) 
            {
                dep[e[i].to]=dep[x]+1;w[e[i].to]=w[x]+(double)e[i].w-mid;
                dfs(e[i].to,x);
            }
    }
    
    void pre_dfs(int x,int fa)
    {
        size[x]=1;mx[x]=0;
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa&&!b[e[i].to]) 
            {
                pre_dfs(e[i].to,x);
                size[x]+=size[e[i].to];
                if(size[e[i].to]>size[mx[x]]) mx[x]=e[i].to;
            }
    }
    
    void pre_work(int x)
    {
        b[x]=1;
        if(yes)return;int mxdp=0; 
        for(int i=head[x];i;i=e[i].next) if(!b[e[i].to])
            pre_dfs(e[i].to,x);
        for(int i=head[x];i;i=e[i].next)
            if(!b[e[i].to])
            {
                tot=size[e[i].to];minn=INF;
                getrt(e[i].to,x);
                root[++rtnum]=rt;pre_work(rt);
            }
    }
    
    void solve(int x)
    {
        b[x]=1;maxdep=0;
        if(yes)return;int mxdp=0; 
        for(int i=head[x];i;i=e[i].next) if(!b[e[i].to])
        {
            maxdep=0;dep[e[i].to]=1;w[e[i].to]=(double)e[i].w-mid;
            dfs(e[i].to,x);
            mxdp=max(mxdp,maxdep);
            v[maxdep].push_back(e[i].to);
        }
        for(int i=1;i<=mxdp;i++)
            for(int j=0;j<v[i].size();j++)
            {
                top=0;bfs(v[i][j],x);Q.init(mxdp);
                int k;for(k=i;k>low-1;k--) Q.ins(k);
                for(k=1;k<=top;k++)
                {
                    if(w[q[k]]>=0&&dep[q[k]]>=low&&dep[q[k]]<=up) {yes=true;for(int i=1;i<=mxdp;i++) d[i]=-INF,v[i].clear();return;}
                    if(dep[q[k]]>up) break;
                    if(dep[q[k]]<low) Q.ins(low-dep[q[k]]);
                    if(Q.query(up-dep[q[k]])+w[q[k]]>=0) {yes=true;for(int i=1;i<=mxdp;i++) d[i]=-INF,v[i].clear();return;}
                }
                for(k=1;k<=top;k++)d[dep[q[k]]]=max(d[dep[q[k]]],w[q[k]]);
            }
        for(int i=1;i<=mxdp;i++) d[i]=-INF,v[i].clear();
    }
    
    int main()
    {    
        tot=n=read();low=read();up=read();
        for(int i=1;i<n;i++)
        {
            int u=read(),v=read(),w=read();
            ins(u,v,w);    
        } 
        for(int i=1;i<=n;i++)d[i]=-INF;
        double l=0,r=1000000;minn=INF;pre_dfs(1,0);getrt(1,0);double ans=0;
        root[++rtnum]=rt;pre_work(rt);
        while(l+eps<=r)
        {
            mid=(l+r)/2.0;yes=false;
            memset(mark,0,sizeof(mark));
            memset(b,0,sizeof(b));
            for(int i=1;i<=n&&!yes;i++)solve(root[i]);
            if(yes) ans=mid,l=mid;
            else r=mid; 
        }
        
        printf("%0.3lf",ans);
        return 0;
    }
  • 相关阅读:
    hackrank Sorting Array of Strings
    c programming create a file
    spine unity3D(摘自博主softimagewht)
    实现鼠标双击(OnGUI)
    使用Unity NGUIInputField组件输入时发现显示为白色就是看不到字体
    NGUI制作可滚动的文本框(摘,如有侵权,联系删除)
    Unity3d 简单的小球沿贝塞尔曲线运动(适合场景漫游使用)
    MVC简单随笔
    Unity脚本自动添加注释脚本及排版格式
    树和树的分类
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1758.html
Copyright © 2011-2022 走看看