Codeforces 1016F Road Projects

正解思路,感觉应该是先判特殊情况,比如新建的路线可以建在于1-n无关的地方,具体判别方法见代码

然后再判断旧路线两端的最大贡献值,即代码中的ans,枚举1-n线路中的每个节点i,求1-[1,i]节点的最大值和[i+1,n]-n节点的最大值,维护ans即可

#include<iostream>
#include<cstdio> 
#include<cmath>
#include<queue>
#include<vector>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<fstream>
#include<cstdlib>
#include<ctime>
#include<list>
#include<climits>
using namespace std;
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fopen freopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#define scd(a) scanf("%d",&a)
#define scf(a) scanf("%lf",&a)
#define scl(a) scanf("%lld",&a)
#define sci(a) scanf("%I64d",&a)
#define scs(a) scanf("%s",a)
#define left asfdasdasdfasdfasfasdfasfsdfasfdas
typedef long long ll;
const int desll[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
const ll mod=1e9+7;
const int maxn=3e5+7;
const int maxm=1e8+7;
const double eps=1e-4;
int m,n;
int ar[maxn];
set<pair<ll,int> > se1,se2;
pair<int,pair<ll,int> > pal1[maxn],pal2[maxn];
int le1,le2;
vector<pair<int,int> > e[maxn];
int markl[maxn],mark;
set<pair<int,int> > seMa;
ll ans=0,ansMid;
int ansl[maxn];
void dfs(int u,int pre)
{
    if(u==n){
        mark=1;
        markl[u]=1;
        return ;
    }
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i].first;
        if(v==pre)continue;
        dfs(v,u);
        if(mark){
            markl[u]=1;
            return ;
        }
    }
}
void dfs1(int u,int pre,ll sum,int ins)
{
    pal1[le1].first=ins;
    pal1[le1].second.first=sum;
    pal1[le1++].second.second=u;
    if(u==n){
        ansMid=sum;
    }
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i].first;
        if(v==pre)continue;
        dfs1(v,u,sum+e[u][i].second,ins+markl[v]);
    }
}
void dfs2(int u,int pre,ll sum,int ins)
{
    pal2[le2].first=ins;
    pal2[le2].second.first=sum;
    pal2[le2++].second.second=u;
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i].first;
        if(v==pre)continue;
        dfs2(v,u,sum+e[u][i].second,ins+markl[v]);
    }
}
int main()
{
    scd(n);
    scd(m);
    for(int i=1;i<n;i++){
        int a,b,c;
        scd(a);scd(b);scd(c);
        e[a].push_back(make_pair(b,c));
        e[b].push_back(make_pair(a,c));
        seMa.insert(make_pair(a,b));
        seMa.insert(make_pair(b,a));
    }
    memset(markl,0,sizeof(markl));
    mark=0;
    le1 = le2 = 0;
    ans=0,ansMid=0;
    dfs(1,0);//求1-n所经过的各个节点
    dfs1(1,0,0,0);
    dfs2(n,0,0,0);
    sort(pal1,pal1+le1);
    sort(pal2,pal2+le2);
    for(int i=1;i<=n;i++){//看新建线路能否建在与1-n无关的地方,若能,其实后面的while维护ans可省略
        int ins=0;
        if(markl[i]){
            for(int j=0;j<e[i].size();j++){
                int x=e[i][j].first;
                if(markl[x]==0)ins++;
            }
        }
        else{
            ins=e[i].size();
        }
        if(ins>=2){
            ans=ansMid;
            break;
        }
    }

    int maxNum=pal1[le1-1].first;
    int be=0;
    for(int i=0;i<le2;i++){
        if(pal2[i].first==maxNum)break;
        se2.insert(pal2[i].second);
        be=i;
    }
    int ins=0,res=0;
    while(res<maxNum){//维护ans
        while(pal1[ins].first<=res){
            se1.insert(pal1[ins].second);
            ins++;
        }
        auto au1=se1.end();
        auto au2=se2.end();
        au1--;
        au2--;
        if(seMa.count(make_pair(au1->second,au2->second))){//若两个节点本身相连,即都在1-n的主线路上,则需退一步判次大值
            if(au1!=se1.begin()){
                au1--;
                ans = max(ans, au1->first+au2->first);
                au1++;
            }
            if(au2!=se2.begin()){
                au2--;
                ans = max(ans, au1->first+au2->first);
                au2++;
            }
        }
        else ans = max(ans, au1->first+au2->first);
        res++;
        while(pal2[be].first+res==maxNum){
            se2.erase(pal2[be].second);
            be--;
        }
    }
    //cout<<maxNum<<" "<<ansMid<<" "<<ans<<endl;
    for(int i=0;i<m;i++){
        int ins;
        scd(ins);
        printf("%I64d
",min(ansMid,ans+ins));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wa007/p/9445025.html