Codeforces 1016 F. Road Projects —— bfs,枚举,思维,求加一条边使得树上1,n最短路最长

This way

题意:

给你一棵树,每条边都有一个权值,q个询问,问你如果加上一条权值为v的边(不能和原有的边重复),从1到n的最短路最长是多少。

题解:

首先可以知道的一点,既然不能制造重边,它的最短路一定是不会增加的,我们只能让最短路尽量不要减小。那么就是说我们要选两个点x,y加一条边使得min(dis[1][x]+dis[n][y]+v,dis[1][y]+dis[n][x]+v,dis[1][n])最大。
v和dis[1][n]都是已经确定了的,那么就是找两个点使得min(dis[1][x]+dis[n][y],dis[1][y]+dis[n][x])最大。
经过一些思考,可以得出以下结论:
假设dis[1][x]是最小的,然后我们要取的是dis[1][x]+dis[2][y],
也就是说dis[1][x]+dis[2][y]<=dis[2][x]+dis[1][y]
也就是dis[1][x]-dis[1][y]<=dis[2][x]-dis[2][y]
那么我们只需要找到dis的差比dis[1][x]-dis[1][y]的大的所有数中dis[2][y]最大的即可。
于是我们用一个集合维护所有的dis[2],然后根据dis[1][x]-dis[1][y]从小到大枚举所有的点,然后查找在multiset中的最大值即可。这个值用过了就删掉,这样子就能保证单调性。然后还要注意和x有连边的在multiset中的所有点先删掉,在对这个点操作完之后加上。
代码是队友写的,但是思想是这么个思想。

/****************************
* Author : 水娃             *
* Date : 2020-08-01-21.09.03*
****************************/
#pragma GCC optimize(3,"Ofast","inline")
#include
using namespace std;
#define mst(a,b) memset(a,b,sizeof(a))
#define ll long long
#define debug(a) cout<<#a<<" is "<<a<<"\n"
#define ull unsigned long long
#define fi first
#define se second
typedef pair<int,int>pii;
typedef pair<ll,int>pli;
typedef pair<int,ll>pil;
typedef pair<ll,ll>pll;
const ull mo=(ull)1e9+7;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
struct N
{
    int pos;
    ll val1,val2;
    bool operator<(const N& x)const
    {
        return val1-val2<x.val1-x.val2;
    }
}a[310000];

int n,q;
ll dis1[310000],dis2[310000];
struct node
{
    int pos;
    ll val;
};
vector<node>v[310000];
int vis1[310000],vis2[310000];
void bfs1(int st)
{
    queue<node>qwq;
    qwq.push({st,0});
    vis1[st]=1;
    node cur,nt;
    while(!qwq.empty())
    {
        cur=qwq.front();
        qwq.pop();
        for(int i=0;i<v[cur.pos].size();i++)
        {
            nt.pos=v[cur.pos][i].pos;
            if(!vis1[nt.pos])
            {
                nt.val=cur.val+v[cur.pos][i].val;
                dis1[nt.pos]=nt.val;
                vis1[nt.pos]=1;
                qwq.push(nt);
            }
        }
    }
}
void bfs2(int st)
{
    queue<node>qwq;
    qwq.push({st,0});
    vis2[st]=1;
    node cur,nt;
    while(!qwq.empty())
    {
        cur=qwq.front();
        qwq.pop();
        for(int i=0;i<v[cur.pos].size();i++)
        {
            nt.pos=v[cur.pos][i].pos;
            if(!vis2[nt.pos])
            {
                nt.val=cur.val+v[cur.pos][i].val;
                dis2[nt.pos]=nt.val;
                vis2[nt.pos]=1;
                qwq.push(nt);
            }
        }
    }
}

multiset<ll>st;
ll gao()
{
    for(int i=1;i<=n;i++)
    {
        st.insert(dis2[i]);
    }
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        auto p=st.find(a[i].val2);
        st.erase(p);
        int curpos=a[i].pos;
        for(int j=0;j<v[curpos].size();j++)
        {
            p=st.find(dis2[v[curpos][j].pos]);
            st.erase(p);
        }
        if(!st.empty())
        {
            p=st.end();
            p--;
            ans=max(ans,*p+a[i].val1);
        }
        for(int j=0;j<v[curpos].size();j++)
        {
            st.insert(dis2[v[curpos][j].pos]);
        }
    }
    return ans;
}
void work()
{
    cin>>n>>q;
    int x,y;
    ll val;
    for(int i=1;i<n;i++)
    {
        cin>>x>>y>>val;
        v[x].push_back({y,val});
        v[y].push_back({x,val});
    }
    bfs1(1);
    bfs2(n);
    for(int i=1;i<=n;i++)
    {
        a[i].pos=i;
        a[i].val1=dis1[i];
        a[i].val2=dis2[i];
    }
    sort(a+1,a+n+1);

    for(int i=1;i<=n;i++)
    {
        cout<<a[i].pos<<" "<<a[i].val1<<" "<<a[i].val2<<"\n";
    }

    ll tmp=gao(),w;
    while(q--)
    {
        cin>>w;
        cout<<min(tmp+w,dis1[n])<<"\n";
    }
}
int main()
{
    ///ios::sync_with_stdio(0);
    ///cin.tie(0);cout.tie(0);
    ///int T;cin>>T;while(T--)
        work();
    return 0;
}

你可能感兴趣的:(2600,想法,最短路)