zoukankan      html  css  js  c++  java
  • [BZOJ 2282] 消防

    Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2282

    Solution:

    看到球最大值最小   ------>   想到二分答案

    首先要推导出一些性质:

    1、这条路径一定在树的直径上

    感性证明:直径上的每个点通向直径末端的路径都是这个方向从该点出发的最长距离

    于是如果将答案路径引上直径的分支必定不会使答案更优

    2、设非直径点到直径的最长距离为$len_{not}$,选取的路径到直径两端的距离分别为$len_{on1}$,$len_{on2}$

    该路径的答案为$max(len_{not},len_{on1},len_{on2})$

    感性证明:如果路径长度达不到直径,同上述直径上点的性质,则新增的最远点只可能为直径的两端

    接下来先预处理$len_{not}$,以其为下界在直径上二分两端缩减的距离

    注意:此题结果只能为简单路径,因此如果$s>len_{直径}$,则输出$len_{not}$即可

    要仔细审题啊……

    Code:

    //by NewErA
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef pair<int,int> P;
    
    const int MAXN=3e5+5;
    int n,s,d[MAXN],dia[MAXN],f[MAXN],rt1,rt2,cnt=0,D;
    bool on_dia[MAXN];
    vector<P> a[MAXN];
    
    void bfs(int st)
    {
        memset(d,-1,sizeof(d));
        d[st]=0;queue<int> q;q.push(st);
        while(!q.empty())
        {
            int cur=q.front();q.pop();
            for(int i=0;i<a[cur].size();i++)
            {
                P t=a[cur][i];
                if(d[t.first]==-1)
                {
                    if(on_dia[t.first]) d[t.first]=d[cur];
                    else d[t.first]=t.second+d[cur];
                    q.push(t.first);f[t.first]=cur;
                }
            }
        }
    }
    
    bool check(int k)
    {
        int l=1,r=cnt;
        while(dia[1]-dia[l+1]<=k && l<cnt) l++;
        while(dia[r-1]<=k && r>1) r--;
        return dia[l]-dia[r]<=s;
    }
    
    int main()
    {
        cin >> n >> s;
        for(int i=1;i<n;i++) 
        {
            int x,y,z;cin >> x >> y >> z;
            a[x].push_back(P(y,z));a[y].push_back(P(x,z));
        }
        bfs(1);for(int i=1;i<=n;i++) if(d[i]>d[rt1]) rt1=i;
        bfs(rt1);for(int i=1;i<=n;i++) if(d[i]>d[rt2]) rt2=i;  //求直径
        
        D=d[rt2];
        
        dia[++cnt]=d[rt2];on_dia[rt2]=true;
        while(rt2!=rt1)
        {
            rt2=f[rt2];
            dia[++cnt]=d[rt2];on_dia[rt2]=true;
        }
        bfs(rt2);  //处理出直径上的点,将其的d值设为0
        
        int l=0,r=D;
        for(int i=1;i<=n;i++) l=max(l,d[i]);
        if(s<D)
            while(l<=r)
            {
                int mid=(l+r)>>1;
                if(check(mid)) r=mid-1;
                else l=mid+1;
            }
        cout << l;
        return 0;
    }

    Review:

    1、最大值最小类的问题,使用二分答案来求解

    2、还是要注意审题啊,题目求的是简单路径

  • 相关阅读:
    Go语言实战_自己定义OrderedMap
    计算机图形学(二)输出图元_3_画线算法_2_DDA算法
    hibernate---java.lang.UnsupportedOperationException: The user must supply a JDBC connection
    OpenCV从入门到放弃(五):像素!
    ibatis 开发中的经验 (三)Struts+Spring+Ibatis 开发环境搭建
    HDU4911-Inversion
    hdu
    Maximum Likelihood Method最大似然法
    最小二乘法least square
    PASCAL VOC数据集The PASCAL Object Recognition Database Collection
  • 原文地址:https://www.cnblogs.com/newera/p/9108963.html
Copyright © 2011-2022 走看看