第三题
思考过程:
本质上是连通性的问题,最大值和最小值是否连通,将其划分到不同的连通分量(不需要强连通、双连通)中,记录每个连通分量的极大值和极小值,然后将各个连通分量的极差输出即可。考虑使用dfs,得到一条dfs路径,并维护该条路径上的两个极值。->需要注意的是,应该对每一个点都进行dfs,为了防止存在如下所示的情况,此时会缺失一条路径CB。
因此,其时间复杂度会变为O(nm),可能会超时。
可否利用类似于树的结构来进行维护呢?->可能会存在环
可否先进行缩点来减少边数和点数呢?->但是如果本身就是一条链结构,缩点将毫无意义
首先缩点,去掉环。每一个点维护一个数值对,(max,min),分别代表的是以该点为起点的路径的极值,再利用边(a,b),可以使用b点的极值来更新a点的极值。
存在的问题:需要重新建图,因为如果仅仅使用belong来判断是否需要移动的话,不能解决代表该连通分量的同步的问题。
//tarjan缩点
//图的存储结构
struct edge {
int from, to, next;
};
vector<edge> E;
int h[NMAX];
//tarjan变量
stack<int > S;
int dfn[NMAX], low[NMAX],belong[NMAX];
void tarjan(int x) {
low[x] = dfn[x] = ++tot;
//标记vis
vis[x] = 1;
S.push(x);
//遍历x联通的每一个点
for (int i = h[x]; i != -1; i = E[i].next) {
if (!dfn[E[i].to]) {
tarjan(E[i].to);
low[x] = min(low[x], low[E[i].to]);
}
else if (dfn[E[i].to]) low[x] = min(low[x], dfn[E[i].to]);
}
//进行强联通分量的查找
if (low[x] == dfn[x]) {
++id;
int now = 0;
while (now != x) {
now = S.top();
S.pop();
belong[now] = id;
}
}
}
is[]//代表是否被遍历,或者max和min值是否被更新
D[]{int value,int max,int min}
pair<int ,int> dfs(int x)
{
for{
//遍历所有的节点
(rmax,rmin)=dfs(child);
D[x].max=max(D[x].max,rmax);
D[x].min=min(D[x].min,rmin);
}
return pair(max,min);
}
参考思路:
//引自他人代码,见参考链接
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int A = 1e6 + 10;
const int B = 3e5 + 10;
class Gra{
public:
int v, next;
}g[A<<1];
class Node{
public:
int id, val;
bool operator<(const Node& rhs) const{
return val < rhs.val;
}
}node[B];
int head[B], tot, ans, mn, mx, a[B];
bool vis[B];
void add (int u, int v) {
g[tot].v = v;
g[tot].next = head[u];
head[u] = tot++;
}
void init() {
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
tot = 0;
}
void dfs(int u) {
if (vis[u]) return;
vis[u] = 1;
mx = max(mx, a[u]);
ans = max(ans, mx - mn);
for (int i = head[u]; i != -1; i = g[i].next) {
int v = g[i].v;
dfs(v);
}
}
int main() {
init();
int n, m;
cin >> n >> m; //输入图点数和边数
for (int i = 1; i <= n; i++) {
node[i].id = i;
cin >> a[i];
node[i].val = a[i];
}
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v; //输入m条边的信息,(u, v)表示有一条u到v的边
add(u, v);
}
sort(node + 1, node + 1 + n);
ans = 0;
for (int i = 1; i <= n; i++) {
mn = mx = node[i].val;
dfs(node[i].id);
}
cout << ans << endl;
return 0;
}