#447 Div2 E

题意

给出一个由有向边构成的图,每条边上有蘑菇,假设有 \(n\) 个蘑菇,那么第一次走过这条边可以获得 \(n\) 个蘑菇,第二次 \(n-1\),第三次 \(n-1-2\),第四次 \(n-1-2-3\),后面类推,直至为 \(0\)。问从选定点出发最多可以获得几个蘑菇。

分析

Tarjan 算法缩点,重新给点标号(缩点),且保证了拓扑排序中靠后的点先标号,对于缩完点后的有向无环图,DP去求最长路。(对于拓扑排序后的序列,根据拓扑排序的性质,可以从后往前DP)

拓扑排序保证了:对于有向边 \(a-b\),\(a\) 一定在 \(b\) 前面。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 10;
struct Edge {
int v, w, nxt;
}e[N];
int head[N], cnt;
void addEdge(int u, int v, int w) {
e[cnt].v = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
int n, m, c, nn, vis[N], dfn[N], low[N];
int f[N]; // 被缩成的新点的序号
ll sup[N]; // 这个新点能提供的贡献
stack<int> sta;
vector<int> G[N];
void tarjan(int u) { // 找强连通分量
sta.push(u);
dfn[u] = low[u] = ++c;
vis[u] = 1;
for(int i = head[u]; ~i; i = e[i].nxt) {
int v = e[i].v;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(vis[v] && low[u] > dfn[v]) {
low[u] = dfn[v];
}
}
if(low[u] == dfn[u]) {
++nn;
while(1) {
int id = sta.top();
G[nn].push_back(id);
f[id] = nn;
sta.pop();
vis[id] = 0;
if(id == u) break;
}
}
}
ll calc(int w) {
int d = sqrt(2 * w);
while(d * d + d > 2 * w) d--;
return 1LL * w * (d + 1) - (1LL * d * (d + 1) * (2 * d + 1) / 6 + d * (d + 1) / 2) / 2;
}
ll dp[N];
int main() {
memset(head, -1, sizeof head);
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addEdge(u, v, w);
}
nn = n;
for(int i = 1; i <= n; i++) {
if(!dfn[i]) tarjan(i);
}
// 计算每个强连通分量缩成的点能提供的贡献
for(int i = 1; i <= n; i++) {
for(int j = head[i]; ~j; j = e[j].nxt) {
int v = e[j].v;
if(f[i] == f[v]) sup[f[i]] += calc(e[j].w);
}
}
int s;
scanf("%d", &s);
s = f[s];
for(int i = n + 1; i <= nn; i++) {
for(int j = 0; j < G[i].size(); j++) {
int q = G[i][j];
for(int p = head[q]; ~p; p = e[p].nxt) {
int v = e[p].v;
if(f[q] != f[v])
dp[i] = max(dp[i], dp[f[v]] + sup[f[v]] + e[p].w);
}
}
}
cout << sup[s] + dp[s] << endl;
return 0;
}

最新文章

  1. 快速Android开发系列通信篇之EventBus
  2. [转]:Delphi中Format的字符串格式化使用说明
  3. Linux Network Related Drive
  4. CLR如何调用虚方法、属性和事件
  5. centos5.4_x64 red5 1.0安装部署
  6. javascript --执行上下文,作用域
  7. MinGW中的头文件路径级环境变量设置
  8. [Daily] 2014-4-22
  9. javascript每日一练(十)——运动二:缓冲运动
  10. SVN版本控制的使用
  11. 怎样将word文件转化为Latex文件:word-to-latex-2.56具体解释
  12. python_如何进行反向迭代和实现反向迭代?
  13. Oracle:常用的一些基本操作
  14. 20175226 2018-2019-2 《Java程序设计》第六周学习总结
  15. 论文笔记:Auto-ReID: Searching for a Part-aware ConvNet for Person Re-Identification
  16. Java中的instanceof和isInstance基础讲解
  17. vue router获取整条路径参数
  18. Go之viper配置
  19. 服务跟踪sleuth和可视化跟踪工具Zipkin
  20. 用JS制作一个信息管理平台(1)

热门文章

  1. [HDU5956]The Elder
  2. BZOJ 3224 Tyvj 1728 普通平衡树 | Splay 板子+SPlay详细讲解
  3. [Leetcode] word break ii拆分词语
  4. angular js自定义service的简单示例
  5. PHP 抽象类,接口,抽象方法,静态方法
  6. 【hdu3080】01背包(容量10^7)
  7. 【HDU5772】String Problem [网络流]
  8. vue 数组、对象 深度拷贝和赋值
  9. Swift 学习之二十一:?和 !(详解)
  10. iOS 中捕获程序崩溃日志 (2014-04-22 17:35:59)