https://www.luogu.org/problemnew/show/P4742
题目背景
[Night - 20:02[Night−20:02 P.M.]P.M.]
夜空真美啊……但是……快要结束了呢……
题目描述
一天的活动过后,所有学生都停下来欣赏夜空下点亮的风筝。CurtisCurtis NishikinoNishikino想要以更近的视角感受一下,所以她跑到空中的风筝上去了(这对于一个妹子来说有点匪夷所思)! 每只风筝上的灯光都有一个亮度 k_iki. 由于风的作用,一些风筝缠在了一起。但是这并不会破坏美妙的气氛,缠在一起的风筝会将灯光汇聚起来,形成更亮的光源!
CurtisCurtis NishikinoNishikino已经知道了一些风筝间的关系,比如给出一对风筝(a,b)(a,b), 这意味着她可以从 aa 跑到 bb上去,但是不能返回。
现在,请帮她找到一条路径(她可以到达一只风筝多次,但只在第一次到达时她会去感受上面的灯光), 使得她可以感受到最多的光亮。同时请告诉她这条路径上单只风筝的最大亮度,如果有多条符合条件的路径,输出能产生最大单只风筝亮度的答案。
输入输出格式
输入格式:
第一行两个整数 nn 和 mm. nn 是风筝的数量, mm 是风筝间关系对的数量.
接下来一行 nn 个整数 k_iki.
接下来 mm 行, 每行两个整数 aa 和 bb, 即CurtisCurtis可以从 aa 跑到 bb.
输出格式:
一行两个整数。CurtisCurtis在计算出的路径上感受到的亮度和,这条路径上的单只风筝最大亮度.
输入输出样例
输入样例#1: 复制5 5 8 9 11 6 7 1 2 2 3 2 4 4 5 5 2输出样例#1: 复制
41 11
说明
对于 20\%20% 的数据, 0<n \le 5\times10^3, \ 0 < m \le 10^40<n≤5×103, 0<m≤104.
对于 80\%80% 的数据, 0 < n \le 10^5, \ 0 < m \le 3\times10^50<n≤105, 0<m≤3×105.
对于 100\%100% 的数据, 0<n\le2\times10^5,\ 0<m\le5\times10^5,\ 0<k\le2000<n≤2×105, 0<m≤5×105, 0<k≤200.
思路:tarjan缩点+拓扑DP,其实DP就是最短路松弛操作。
///缩点+拓扑DP #include<bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; const int maxn = 2e5+4; int n,m,cnt,color; int a[maxn],DFN[maxn],LOW[maxn],belong[maxn],dis[maxn],maxdis[maxn],maxval[maxn],in[maxn],sumval[maxn]; bool vis[maxn]; stack<int>s; vector <int> G[maxn],NG[maxn]; void tarjan(int x){ DFN[x]=LOW[x]=++cnt; vis[x]=true; s.push(x); for(int i=0;i<G[x].size();i++){ int to=G[x][i]; if(!DFN[to]){ tarjan(to); LOW[x]=min(LOW[x],LOW[to]); }else if(vis[to]){ LOW[x]=min(LOW[x],DFN[to]); } } if(LOW[x]==DFN[x]){ int temp; color++; maxval[color]=0; do{ temp=s.top(); s.pop(); vis[temp]=false; belong[temp]=color; sumval[color]+=a[temp]; maxval[color]=max(maxval[color],a[temp]); }while(temp!=x); } } ///dis[x]/以x为终点的最大距离和,maxdis[x]/以x为终点的最大距离间隔 void tpu(){ fill(dis,dis+color+1,-INF); queue<int>Q; for(int i=1;i<=color;i++){ if(in[i]==0){ dis[i]=sumval[i]; maxdis[i]=maxval[i]; Q.push(i); } } while(!Q.empty()){ int u=Q.front(); Q.pop(); for(int i=0;i<NG[u].size();i++){ int to=NG[u][i]; in[to]--; if(dis[to]<dis[u]+sumval[to]){///如果从u-》to的价值和更加大,就更新,而且要更新maxdis,为maxval[to]和之前dis[u]的更大的那个 dis[to]=dis[u]+sumval[to]; maxdis[to]=max(maxdis[u],maxval[to]); }else if(dis[to]==dis[u]+sumval[to]){///如果相等,就要考虑maxdis的更新 maxdis[to]=max(maxdis[to],maxdis[u]); } if(in[to]==0){ Q.push(to); } } } int anssum=0,ansmax=0; for(int i=1;i<=color;i++){ if(anssum<dis[i]){ anssum=dis[i]; ansmax=maxdis[i]; }else if(anssum==dis[i]){ ansmax=max(ansmax,maxdis[i]); } } printf("%d %d\n",anssum,ansmax); } int main(){ int x,y; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=0;i<m;i++){ scanf("%d%d",&x,&y); G[x].push_back(y); } for(int i=1;i<=n;i++){ if(!DFN[i]){ tarjan(i); } } for(int i=1;i<=n;i++){ for(int j=0;j<G[i].size();j++){ int to=G[i][j]; if(belong[i]!=belong[to]){ NG[belong[i]].push_back(belong[to]); in[belong[to]]++; } } } tpu(); return 0; }