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\n",min(ansMid,ans+ins)); } return 0; }