• 洛谷P3387 【模板】缩点


    题目链接:

    kma

    题目分析:

    缩点之后很明显是个DAG,跑一遍toposort顺便dp
    方程(ans[v] = max(ans[u] + w[v], ans[v])),ans是到这个连通块的最大点权和,w是这个连通块的点权
    注意缩点之后两个连通块之间可能会有很多边,从连通块内不同的点发出,正反分别只能连一次,否则toposort会凉

    代码:

    #include <bits/stdc++.h>
    #define N (100000 + 10)
    using namespace std;
    inline int read() {
    	int cnt = 0, f = 1; char c = getchar();
    	while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    	while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
    	return cnt * f;
    }
    int n, m, x, y, to[N], first[N], nxt[N], tot, sta[N], insta[N], w[N], v[N], id[N];
    int nxt_[N], first_[N], to_[N], tot_, in[N], low[N], dfn[N], sign, top, cnt;
    int ans[N], gmax, fa[N];
    int get_father(int x) {return x == fa[x] ? x : fa[x] = get_father(fa[x]);}
    inline void Add(int x, int y) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y;}
    inline void Add_(int x, int y) {nxt_[++tot_] = first_[x], first_[x] = tot_, to_[tot_] = y;}
    void tarjan(int u) {
    	low[u] = dfn[u] = ++sign, sta[++top] = u, insta[u] = 1;
    	for (register int i = first[u]; i; i = nxt[i]) 
    		if (!dfn[to[i]]) tarjan(to[i]), low[u] = min (low[u], low[to[i]]);
    		else if (insta[to[i]] && dfn[to[i]] < low[u]) low[u] = dfn[to[i]];
    	if (low[u] == dfn[u]) {
    		++cnt;
    		do {w[id[sta[top]] = cnt] += v[sta[top]], insta[sta[top]] = 0;} while(u != sta[top--]);
    	}
    }
    inline void toposort() {
    	queue <int> q;
    	for (int i = 1; i <= cnt; i++) if (!in[i]) q.push(i), ans[i] = w[i], gmax = max(gmax, ans[i]);
    	while (!q.empty()) {
    		int u = q.front(); q.pop();
    		for (register int i = first_[u]; i; i = nxt_[i]) {
    			int v = to_[i]; --in[v];
    			if (!in[v]) q.push(v), ans[v] = max(ans[v], ans[u] + w[v]), gmax = max(gmax, ans[v]);
    		}
    	}
    }
    int main() {
    	n = read(), m = read();
    	for (register int i = 1; i <= n; ++i) v[i] = read();
    //	for (register int *t = v + 1; t <= v + n + 1; ++t) *t = read();
    	for (register int i = 1; i <= m; ++i) x = read(), y = read(), Add(x, y);
    	for (register int i = 1; i <= m; ++i) {
    		if (!dfn[i]) tarjan(i);
    	}
    	register int *t = fa + 1; for (;t <= fa + cnt + 1;) {*t = t - fa; ++t;}
    	for (register int i = 1; i <= n; ++i) 
    		for (register int j = first[i]; j; j = nxt[j]) {
    			register int v = to[j];
    			if (id[v] != id[i]) {
    				register int x = get_father(id[i]), y = get_father(id[v] + cnt);
    				if (x == y) continue;
    				Add_(id[i], id[v]), ++in[id[v]], fa[y + cnt] = x;
    			}
    		}
    	toposort();
    	printf("%d", gmax);
    	return 0;
    }
    
  • 相关阅读:
    [日志]一个父亲给儿子的忠告
    [健康]预防手足口病中医有妙方
    [日志]教你怎么用一句话把人弄的又好气又好笑
    [健康]出汗与人健康
    [健康]四招,清除体内“垃圾”
    [健康]生病了绝对不能吃的东西
    [日志]塑造自己品牌的方法
    [健康]肾的保健按摩
    [日志]经典道歉短信
    [日志]几个笑话顿悟人生道理
  • 原文地址:https://www.cnblogs.com/kma093/p/11330654.html
Copyright © 2020-2023  润新知