标签:缩点 JZOJ int 联考 dfn MAXN low MAXM col
题意
给出一个图,上面有若干连通块。
对于每个连通块,为有向边组成的图,每个点上有点权。
最多在\(K+1\)个连通块操作,使得遍历这个连通块获得的点权之和最大。
思路
将每个连通块上的环缩点,变成一个DAG然后dp即可。
代码
#include <queue>
#include <stack>
#include <cstdio>
#include <algorithm>
const int MAXN = 200001, MAXM = 2000001;
std::stack<int> s;
std::queue<int> q;
int n, m, k, tot, tot1, dfncnt, col, ans;
int low[MAXN], dfn[MAXN], in_s[MAXN], scc[MAXN], ver[MAXM], next[MAXM], head[MAXM];
int ver1[MAXM], next1[MAXM], head1[MAXM], deg[MAXM];
int vw[MAXN], vv[MAXN], fa[MAXN], used[MAXN];
struct node {
int id, a;
} f[MAXN];
void add(int u, int v) {
ver[++tot] = v;
next[tot] = head[u];
head[u] = tot;
}
void add1(int u, int v) {
ver1[++tot1] = v;
next1[tot1] = head1[u];
head1[u] = tot1;
}
void tarjan(int u) {
low[u] = dfn[u] = ++dfncnt;
s.push(u);
in_s[u] = 1;
int v;
for (int i = head[u]; i; i = next[i])
if (!dfn[v = ver[i]]) {
tarjan(v);
low[u] = std::min(low[u], low[v]);
} else if (in_s[v])
low[u] = std::min(low[u], dfn[v]);
if (dfn[u] == low[u]) {
++col;
fa[col] = col;
int p;
while ((p = s.top()) != u) {
vv[col] += vw[p];
scc[p] = col;
in_s[p] = 0;
s.pop();
}
scc[p = s.top()] = col;
vv[col] += vw[p];
f[col].a = vv[col];
f[col].id = col;
in_s[p] = 0;
s.pop();
}
}
int find(int x) {
return fa[x] = fa[x] == x ? x : find(fa[x]);
}
void dp() {
for (int i = 1; i <= col; i++)
if (!deg[i])
q.push(i);
while (q.size()) {
int u = q.front(), y;
q.pop();
for (int i = head1[u]; i; i = next1[i]) {
y = ver1[i];
f[y].a = std::max(vv[y] + f[u].a, f[y].a);
deg[y]--;
if (!deg[y])
q.push(y);
}
}
}
int cmp(node x, node y) {
return x.a > y.a;
}
int main() {
freopen("azeroth.in", "r", stdin);
freopen("azeroth.out", "w", stdout);
scanf("%d %d", &n, &m);
for (int i = 1, a, b; i <= m; i++) {
scanf("%d %d", &a, &b);
if (a != b)
add(a, b);
}
for (int i = 1; i <= n; i++)
scanf("%d", &vw[i]);
scanf("%d", &k);
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 = next[j])
if (scc[i] != scc[ver[j]]) {
int f1 = find(scc[i]), f2 = find(scc[ver[j]]);
add1(scc[i], scc[ver[j]]);
deg[scc[ver[j]]]++;
fa[f1] = f2;
}
dp();
std::sort(f + 1, f + col + 1, cmp);
k++;
for (int i = 1, f1; i <= col && k; i++)
if (!used[f1 = find(f[i].id)]) {
used[f1] = 1;
ans += f[i].a;
k--;
}
printf("%d", ans);
}
坑
并查集出锅
数组大小没开够(边与点)
标签:缩点,JZOJ,int,联考,dfn,MAXN,low,MAXM,col 来源: https://www.cnblogs.com/HSZGB/p/15120847.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。