ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【缩点 动态规划】JZOJ_4253. 【五校联考7day2】QYQ在艾泽拉斯

2021-08-09 22:03:01  阅读:215  来源: 互联网

标签:缩点 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. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有