题目背景
[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.
一道DAGdp 的算是简单题吧
我错误的思想一直卡55分
wa了n发
最后看了题解写了topu序dp过了 枚举indu跑会浪费很多时间
先说思路:
拿到题 发现可以重复走 那就是有环了 然后要求最大链长 很容易想到 树形dp 求树的直径
两者结合 就大概是一道 DAG dp
去掉环 用tarjan缩点 博客有板子
记录每个颜色块的最大值
跑一遍topu序dp
结束
放一下代码吧
一开始不停的超时觉得是优化没到位 一直加黑科技优化QAQ
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
int head[maxn];
int dfn[maxn];
int low[maxn];
bool vis[maxn];
int colour[maxn];
int indu[maxn];
int dist[maxn];
int light[maxn];
int cp[maxn];
int dp[maxn][5];
int mx[maxn];
int tot;
int tot1;
int sum;//联通块个数&&颜色
int dex;
int cnt;
int n, m;
int ans;
struct node{
int to;
int next;
int from;
node() {}
node(int a, int b, int c) : to(a), next(b), from(c) {}
}edge[maxn], edge1[maxn];
void edgeadd(int a, int b){
edge[tot] = node(b, head[a], a);
head[a] = tot++;
}
void edgeadd1(int a, int b){
edge1[tot1] = node(b, head[a], a);
head[a] = tot1++;
}
void init(){
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(indu, 0, sizeof(indu));
memset(cp, 0, sizeof(cp));
tot = 0;
tot1 = 0;
sum = 0;
dex = 0;
ans = 0;
}
stack<int> s;
void tarjan(int u){
dfn[u] = low[u] = ++dex;
s.push(u);
vis[u] = 1;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]){
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]){
sum++;
while(1){
int now = s.top();
//cout << now << endl;
colour[now] = sum;
s.pop();
vis[now] = 0;
if(now == u) break;
}
}
}
void tsort(){
queue<int>q;
for (int i = 1; i <= n; i++) dp[i][0] = cp[i], dp[i][1] = mx[i];
//dp[i][0] 维护的是走到 i 的点权和,同时 dp[i][1] 维护路径上的点权最大值。
for (int i = 1; i <= sum; i++) if (!indu[i]) q.push(i);
while(!q.empty()){
int nw = q.front();
q.pop();
for (int i = head[nw]; i != -1; i = edge1[i].next){
int v = edge1[i].to;
if (dp[nw][0] + cp[v] > dp[v][0]){
dp[v][0] = dp[nw][0] + cp[v];
dp[v][1] = max(dp[nw][1], mx[v]);//注意这句和下面更新方法的差异
}
if (dp[nw][0] + cp[v] == dp[v][0])
dp[v][1] = max(dp[v][1], dp[nw][1]);
indu[v]--;
if(indu[v] <= 0) q.push(v);
}
}
}
/*void dfs(int u, int pre){
if(dp[pre][0]+cp[u]>dp[u][0]){
dp[u][0]=dp[pre][0]+cp[u];
dp[u][1]=max(dp[pre][1],mx[u]);//注意这句和下面更新方法的差异
}
if(dp[pre][0]+cp[u]==dp[u][0])
dp[u][1]=max(dp[u][1],dp[pre][1]);
for(int i = head[u]; i != -1; i = edge1[i].next){
int v = edge1[i].to;
if(v == pre)
continue;
dfs(v, u);
}
}*/
int main(){
scanf("%d%d", &n, &m);
init();
int x, y;
for(int i = 1; i <= n; i++)
scanf("%d", &light[i]);
for(int i = 1; i <= m; i++){
scanf("%d%d", &x, &y);
edgeadd(x, y);
}
for(int i = 1; i <= n; i++){
if(!dfn[i])
tarjan(i);
}
memset(head, -1, sizeof(head));
for(int i = 0; i < m; i++){
int o, g;
o = colour[edge[i].from];
g = colour[edge[i].to];
if(o != g){
edgeadd1(o, g);
indu[g]++;
}
}
for(int i = 1; i <= n; i++){
cp[colour[i]] += light[i];
mx[colour[i]] = max(light[i], mx[colour[i]]);
}
/*for(int i = 1; i <= sum; i++){
if(!indu[i]){
dfs(i, 0);
}
}*/
tsort();
int res=1;
for (int i = 2; i <= sum; i++)
if (dp[i][0] > dp[res][0] || dp[i][0] == dp[res][0] && dp[i][1] >= dp[res][1]) res = i;
printf("%d %d", dp[res][0], dp[res][1]);
return 0;
}