传送门:https://www.luogu.org/problemnew/show/P3387

首先呢,tarjan找一个图的强连通分量是基于对图的dfs的。这中间开了一个dfn[]代表dfs序,还有个low[]代表该节点在dfs形成的树中能到达的最近的根。然后分情况进行更新(一会儿看我代码吧)。

为了记录一个强联通分量,我们还要在开一个栈来储存当前查找的强连通分量。如果low[x] == dfn[x],那就说明这个点在dfs树种不能往上再爬了,于是就开始弹栈。

对于这道题呢,先用tarjan找出强联通分量,然后缩点建立新图。可以发现,建立的新图是一个拓扑图,所以可以拓扑排序后在图上dp,然而我这么写wa了。翻题解的时候看到了一个更简单的方法:记录每一个点的入度,对于每一个入度为0的点用spfa跑一遍最长路,然后在所有最长路中取一个max即可。

 #include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter printf("\n")
#define space printf(" ")
#define Mem(a) memset(a, 0, sizeof(a))
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-;
const int maxn = 1e5 + ;
inline ll read()
{
ll ans = ;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch))
{
ans = ans * + ch - ''; ch = getchar();
}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < ) x = -x, putchar('-');
if(x >= ) write(x / );
putchar('' + x % );
} vector<int> v[maxn];
int n, m, a[maxn]; int dfn[maxn], low[maxn], cnt = ;
bool in[maxn];
stack<int> st;
int col[maxn], ccol = , val[maxn];
void tarjan(int now)
{
dfn[now] = low[now] = ++cnt;
st.push(now); in[now] = ;
for(int i = ; i < (int)v[now].size(); ++i)
{
if(!dfn[v[now][i]]) //这个联通块还没找完
{
tarjan(v[now][i]);
low[now] = min(low[now], low[v[now][i]]);
}
else if(in[v[now][i]]) low[now] = min(low[now], dfn[v[now][i]]); //这个点找到了他所在联通块的祖先节点
}
if(low[now] == dfn[now]) //开始找出联通块中的所有点
{
int x; ccol++; //ccol相当于染色种数,也就是有多少个连通分量
do
{
x = st.top();
in[x] = ; st.pop();
col[x] = ccol; val[ccol] += a[x]; //val[]记录新图上的点的点权
}while(x != now);
}
return;
} vector<int> v2[maxn];
bool du[maxn];
void newGraph(int now)
{
for(int i = ; i < (int)v[now].size(); ++i)
{
int x = col[now], y = col[v[now][i]];
if(x == y) continue; //别忘了两个点在一个联通块的情况
v2[x].push_back(y);
du[y] = ;
}
return;
} int ans = ; int dis[maxn];
bool vis[maxn];
void spfa(int s)
{
Mem(vis);
for(int i = ; i <= ccol; ++i) dis[i] = -INF;
queue<int> q;
q.push(s); vis[s] = ;
dis[s] = val[s];
while(!q.empty())
{
int now = q.front(); q.pop(); vis[now] = ;
for(int i = ; i < (int)v2[now].size(); ++i)
{
if(dis[now] + val[v2[now][i]] > dis[v2[now][i]])
{
dis[v2[now][i]] = dis[now] + val[v2[now][i]];
if(!vis[v2[now][i]]) {q.push(v2[now][i]); vis[v2[now][i]] = ;}
}
}
}
for(int i = ; i <= ccol; ++i) ans = max(ans, dis[i]); //更新答案
}
int main()
{
n = read(); m = read();
for(int i = ; i <= n; ++i) a[i] = read();
for(int i = ; i <= m; ++i)
{
int x = read(), y = read();
v[x].push_back(y);
}
for(int i = ; i <= n; ++i) if(!dfn[i]) tarjan(i); //有的点从一个定点出发可能走不到,就都得判断是否走过
for(int i = ; i <= n; ++i) newGraph(i); //建立新图
for(int i = ; i <= ccol; ++i) if(!du[i]) spfa(i); //对于每一个入度为0的点,跑最长路
write(ans); enter;
return ;
}

tarjan【模板】缩点的更多相关文章

  1. 图论算法-Tarjan模板 【缩点;割顶;双连通分量】

    图论算法-Tarjan模板 [缩点:割顶:双连通分量] 为小伙伴们总结的Tarjan三大算法 Tarjan缩点(求强连通分量) int n; int low[100010],dfn[100010]; ...

  2. Tarjan的缩点&&割点概述

    What is Tarjan? Tarjan,是一种用来解决图的联通性的一种有效途径,它的一般俗称叫做:缩点.我们首先来设想一下: 如果我们有一个图,其中A,B,C构成一个环,那么我们在某种条件下,如 ...

  3. POJ 2186:Popular Cows Tarjan模板题

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 25945   Accepted: 10612 De ...

  4. BZOJ1179 [Apio2009]Atm Tarjan 强连通缩点 动态规划

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1179 题意概括 有一个有向图,每一个节点有一个权值,其中有一些结束点. 现在,你要从S出发,到达任 ...

  5. BZOJ1051 [HAOI2006]受欢迎的牛 Tarjan 强连通缩点

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1051 题意概括 有n只牛,有m个羡慕关系. 羡慕关系具有传递性. 如果A羡慕B,B羡慕C,那么我们 ...

  6. UOJ #146. 【NOIP2015】信息传递 连通分量 tarjan模板题

    http://uoj.ac/problem/146 题解:强连通分量 tarjan模板题.同时试了一下codeblock #include<bits/stdc++.h> using nam ...

  7. tarjan算法+缩点--cojs 908. 校园网

    cojs 908. 校园网 ★★   输入文件:schlnet.in   输出文件:schlnet.out   简单对比时间限制:1 s   内存限制:128 MB USACO/schlnet(译 b ...

  8. 学渣乱搞系列之Tarjan模板合集

    学渣乱搞系列之Tarjan模板合集 by 狂徒归来 一.求强连通子图 #include <iostream> #include <cstdio> #include <cs ...

  9. 洛谷1726 上白泽慧音 tarjan模板

    题目描述 在幻想乡,上白泽慧音是以知识渊博闻名的老师.春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄.因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点.人间 ...

  10. 算法问题实战策略 MEETINGROOM 附一份tarjan模板

    地址 https://algospot.com/judge/problem/read/MEETINGROOM 解答  2-sat 代码样例过了 没有ac. 我又没有正确代码对拍..... 已确认是输出 ...

随机推荐

  1. 【移入移出事件练习】【菜单】【选项卡】 -------this使用

    鼠标移入移出事件练习 建一个长100x100的红色 div,鼠标移入变为200x200绿色 .a { width:100px; height:100px; background-color:red ; ...

  2. 简单的SpringMVC经典案例

    主题:构建一个基于SpringMVC的HelloWord Web 项目 目的:快速体验什么是SpringMVC 方案: 1.创建工程,命名:SpringMVC 2.导包 3.在SRC下添加spring ...

  3. linux_shell_入门

    shell编程入门: 程序员标配:第一个shell脚本 输出 ---- " Hello World !!" 1.先创建一个hello.sh脚本文件 vi hello.sh 然后在输 ...

  4. linux系统编程:cp的另外一种实现方式

    之前,这篇文章:linux系统编程:自己动手写一个cp命令 已经实现过一个版本. 这里再来一个版本,涉及知识点: linux系统编程:open常用参数详解 Linux系统编程:简单文件IO操作 /*= ...

  5. linux系统编程:自己动手写一个ls命令

    ls用于列举目录内容,要实现这个功能,毫无疑问,需要读取目录,涉及到两个api: opendir:DIR *opendir(const char *name), 传文件名,返回一个指针,指向目录序列 ...

  6. Python面试题都在这里了

    转自武沛齐博客:http://www.cnblog.com/wupeiqi/ 第一部分 Python基础篇(80题) 为什么学习Python? 通过什么途径学习的Python? Python和Java ...

  7. python学习之老男孩python全栈第九期_day008知识点总结

    ''''如何打开一个文件模特主妇护士老师.txt1. 文件路径:f:\模特主妇护士老师.txt2. 操作方式:只读:r ,rb ,只写: w, wb ,追加: a , ab,读写:r+ , r+b,写 ...

  8. js-ES6学习笔记-正则的扩展

    1.在ES5中,RegExp构造函数的参数有两种情况.第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag).第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷 ...

  9. 【代码笔记】iOS-去掉NSString中的空格

    一,代码. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, ...

  10. 【读书笔记】iOS-网络-使用推送通知

    一,本地通知 本地通知有64位的最大限制.虽然,你依然可以调度通知,不过到到达的通知数被限定为接近64个,并且按照fireDate的顺序排序,系统会忽略掉其余的通知.这意味着如果现在有64个调用的本地 ...