zoukankan      html  css  js  c++  java
  • [SDOI2011]消防(单调队列,树的直径,双指针)

     消防

     

    2011年

     时间限制: 2 s
     空间限制: 256000 KB
     题目等级 : 大师 Master
     
    题目描述 Description

    某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000)。

    这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。

    现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。

    你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。

    输入描述 Input Description

        输入包含n行:
        第1行,两个正整数n和s,中间用一个空格隔开。其中n为城市的个数,s为路径长度的上界。设结点编号以此为1,2,……,n。
      从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。

    输出描述 Output Description

    输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。

    样例输入 Sample Input

    【样例输入1】

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

    【样例输入2】

    8 6
    1 3 2
    2 3 2 
    3 4 6
    4 5 3
    4 6 4
    4 7 2
    7 8 3  

    样例输出 Sample Output

    【样例输出1】

    5

    【样例输出2】

    5

    数据范围及提示 Data Size & Hint

    对于20%的数据,n<=300。

    对于50%的数据,n<=3000。

    对于100%的数据,n<=300000,边长小等于1000。 

    /*
    20%的数据,就是NOIP那道树网的核。
    100%这么大的数据范围,若直径长度为d,dlogd可能会被卡
    所以就需要一种O(n)的算法。
    
    先bfs两遍求出树的直径(防爆栈),O(n)的
    然后维护 g[i]表示i是路径右端点时,右边那段删掉的直径长度。
    f[i]表示i是路径左端点时,左边那段删掉的直径长度。
    h[i]表示i是直径上的点,每个直径上的点不是都有一棵(或者很多棵)
    由非此直径上点组成的树(森林)嘛,点i到这些子节点中最远的那个的距离。
    然后在这个序列上跑双指针。就是路径长度不是有限制嘛,然后从左到右枚举左端点,然后右端点是非严格单调右移的。
    时间复杂度线性。而对于一段路径区间[l,r],它作为枢纽时的答案为 
    max(max(f[l],g[r]),max{hi,i∈[l,r]}) 
    然后最右边那个怎么搞呢? 单调队列,维护hi最大值啊~ 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    
    #define N 3000007
    #define inf 0x3f3f3f3f
    
    using namespace std;
    int n,m,k,s,t,ans,cnt,num,L,R;
    int head[N],f[N],g[N],h[N],fa[N],vis[N];
    int belong[N],tmp[N],que[N],id[N];
    struct edge{
        int v,net,w;
    }e[N<<1];
    queue<int>q;
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    inline void add(int u,int v,int w)
    {
        e[++cnt].v=v;e[cnt].w=w,e[cnt].net=head[u];head[u]=cnt;
    }
    
    int bfs(int s,int Time)
    {
        int len=0;q.push(s);
        g[s]=0,fa[s]=s,vis[s]=Time;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].net)
            {
                int v=e[i].v;
                if(vis[v]==Time) continue;
                g[v]=g[u]+e[i].w;len=max(len,g[v]);
                fa[v]=u;vis[v]=Time;
                q.push(v);
            }
        }return len;
    }
    
    void solve()
    {
        int i;
        for(s=1,bfs(s,++num),i=1;i<=n;i++)
          if(g[i]>g[s]) s=i;
        for(bfs(s,++num),i=1;i<=n;i++)
          if(g[i]>g[t]) t=i;
        belong[n=1]=t;num++;
        do{
            t=fa[t],belong[++n]=t,vis[t]=num;
        }while(t!=s);
        
        for(i=1;i<=n;i++) f[i]=g[belong[1]]-g[belong[i]];
        for(i=1;i<=n;i++) tmp[i]=g[belong[i]];
        for(i=1;i<=n;i++) h[i]=bfs(belong[i],num);
        for(i=1;i< n;i++) g[i]=tmp[i];g[n]=0;    
    }
    
    int main()
    {
        int x,y,z;
        n=read();m=read();
        for(int i=1;i<n;i++)
        {
            x=read();y=read();z=read();
            add(x,y,z);add(y,x,z);
        }
        solve();
        
        int l=1,r=0;ans=inf;
        for(l=1;l<=n;l++)
        {
            while(r<n && f[r+1]-f[l]<=m)
            {
                ++r;while(L<=R && que[R]<h[r]) R--;
                que[++R]=h[r];id[R]=r;
            }
            ans=min(ans,max(max(f[l],g[r]),que[L]));
            if(id[L]<=l)L++;
        }
        printf("%d
    ",ans);
        return 0;
    }
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    为SharePoint 2010中的FBA创建自定义登录页面
    SharePoint 2010设置问卷调查权限
    无法创建您的个人网站,因为未启用“自助式网站创建”
    等级歧视的死循环[转]
    职业生涯中的10个致命错误
    项目经理须具备所有9 大知识领域
    项目管理工具和技术
    在SharePoint Server 2010中创建“我的网站”
    MATCH_PARENT是什么类型的布局
    Android 在代码中获取手机屏幕的宽高
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7737817.html
Copyright © 2011-2022 走看看