代码堆砌

连通分量

通过 Tarjan对有向图缩点
#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 7, inf = 1e9 + 7;

struct edge {
	int u, v;
} e[N];

int dfn[N], lt[N], st[N], low[N], a[N], siz[N], f[N], indu[N];
int n, m, tim, ans = -inf;

queue <int> q;

vector <int> g[N], G[N];

inline void Tarjan(int u)
{
	low[u] = dfn[u] = ++ tim;
	st[++ st[0]] = u;
	for (int v : g[u])
	{
		if (!dfn[v])
		{
			Tarjan(v);
			low[u] = min(low[v], low[u]);
		}
		else if (!lt[v])
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
	if (dfn[u] == low[u])
	{
		lt[u] = ++ lt[0];
		siz[lt[0]] += a[u];
		while (st[st[0]] != u)
		{
			lt[st[st[0]]] = lt[0];
			siz[lt[0]] += a[st[st[0]]];
			st[0] --;
		}
		st[0] --;
	}
}

int main()
{
	scanf("%lld%lld",&n,&m);
	for (int i = 1; i <= n; ++ i)
	{
		scanf("%lld",&a[i]);
	}
	for (int i = 1; i <= m; ++ i)
	{
		scanf("%lld%lld",&e[i].u,&e[i].v);
		g[e[i].u].push_back(e[i].v);
	}
	for (int i = 1; i <= n; ++ i)
	{
		if (!dfn[i]) Tarjan(i);
	}
	for (int i = 1; i <= m; ++ i)
	{
		int u = lt[e[i].u];
		int v = lt[e[i].v];
		if (u == v) continue;
		G[u].push_back(v);
		indu[v] ++;
	}
	for (int i = 1; i <= lt[0]; ++ i)
	{
//		f[i] = -inf;
		if (indu[i] == 0) 
		{
			q.push(i);
			f[i] = siz[i];
		}
	}
	while (!q.empty())
	{
		int u = q.front();
		q.pop();
		for (int v : G[u])
		{
			f[v] = max(f[v], f[u]+siz[v]);
			indu[v] --;
			if(indu[v] == 0) q.push(v); 
		}
	}
	for (int i = 1; i <= lt[0]; ++ i) ans = max(ans, f[i]);
	printf("%lld",ans); 
	return 0;
}
通过 Tarjan 所求出的割点
#include <bits/stdc++.h>
using namespace std;

int low[21000], dfn[21000], n, m, tim, root, cnt; 
vector <int> g[21000];
bool vis[21000];

inline void Tarjan(int u, int fa)
{
	dfn[u] = low[u] = ++ tim;
	int col = 0;
	for (int v : g[u])
	{
		if (!dfn[v])
		{
			col ++;
			Tarjan(v, u);
			low[u] = min(low[u], low[v]); 
            // 两种割点的判断方式
			if (u == root && col > 1)
			{
				if (!vis[u]) vis[u] = 1, cnt ++;
			}
			if (u != root && dfn[u] <= low[v]) 
			{
				if (!vis[u]) vis[u] = 1, cnt ++;
			}
		}
		else if (fa != v)
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
}

int main()
{
	cin >> n >> m;
	for (int i = 1, u, v; i <= m; ++ i)
	{
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for (int i = 1; i <= n; ++ i)
	{
		if (!dfn[i]) 
		{
			root = i;
			Tarjan(i, 0);
		}
	}
	cout << cnt << '\n'; // 割点数量
	for (int i = 1; i <= n; ++ i)
	{
		if (vis[i]) cout << i << ' '; // 割点
	}
	return 0;
}
通过 Tarjan 所求出的桥
#include <bits/stdc++.h>
using namespace std;

const int KI = 5e6 + 7;
struct edge
{
	int v, nxt; bool flag;
} e[KI];
int dfn[KI], low[KI], lt[KI], hd[KI];
int tim, dcc, n, m, cnt = 1;
vector <int> bridge[KI]; 

inline void addedge(int u, int v)
{
	e[++ cnt].v = v; e[cnt].nxt = hd[u]; hd[u] = cnt;
}

inline void tarjan(int u, int edge_in)
{
	dfn[u] = low[u] = ++ tim;
	for (int i = hd[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (!dfn[v])
		{
			tarjan(v, i);
			low[u] = min(low[u], low[v]);
			if (dfn[u] < low[v])
			{
				e[i].flag = e[i^1].flag = 1; // 该边为桥 
			}
		}
		else if (i != (edge_in^1))
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
}

inline void dfs(int u)
{
	lt[u] = dcc;
	bridge[dcc].push_back(u);
	for (int i = hd[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (lt[v] || e[i].flag) continue;
		dfs(v);
	}
}

int main()
{
	cin >> n >> m;
	for (int i = 1, u, v; i <= m; ++ i)
	{
		cin >> u >> v;
		if (u == v) continue;
		addedge(u, v);
		addedge(v, u);
	}
	for (int i = 1; i <= n; ++ i)
	{
		if (!dfn[i]) tarjan(i, 0);
	}
	return 0;
}
边双连通分量(e-DCC,Tarjan)
#include <bits/stdc++.h>
using namespace std;

const int KI = 5e6 + 7;
struct edge
{
	int v, nxt; bool flag;
} e[KI];
int dfn[KI], low[KI], lt[KI], hd[KI];
int tim, dcc, n, m, cnt = 1;
vector <int> bridge[KI]; 

inline void addedge(int u, int v)
{
	e[++ cnt].v = v; e[cnt].nxt = hd[u]; hd[u] = cnt;
}

inline void tarjan(int u, int edge_in)
{
	dfn[u] = low[u] = ++ tim;
	for (int i = hd[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (!dfn[v])
		{
			tarjan(v, i);
			low[u] = min(low[u], low[v]);
			if (dfn[u] < low[v])
			{
				e[i].flag = e[i^1].flag = 1;
			}
		}
		else if (i != (edge_in^1))
		{
			low[u] = min(low[u], dfn[v]);
		}
	}
}

inline void dfs(int u)
{
	lt[u] = dcc;
	bridge[dcc].push_back(u);
	for (int i = hd[u]; i; i = e[i].nxt)
	{
		int v = e[i].v;
		if (lt[v] || e[i].flag) continue;
		dfs(v);
	}
}

int main()
{
	cin >> n >> m;
	for (int i = 1, u, v; i <= m; ++ i)
	{
		cin >> u >> v;
		if (u == v) continue;
		addedge(u, v);
		addedge(v, u);
	}
	for (int i = 1; i <= n; ++ i)
	{
		if (!dfn[i]) tarjan(i, 0);
	}
	for (int i = 1; i <= n; ++ i)
	{
		if (!lt[i])
		{
			dcc ++; dfs(i);
		}
	}
	cout << dcc << '\n';
	for (int i = 1; i <= dcc; ++ i)
	{
		cout << bridge[i].size() << ' ';
		for (int u : bridge[i])
		{
			cout << u << ' ';
		}
		cout << '\n';
	}
	return 0;
}
点双连通分量(v-DCC,Tarjan)
#include <bits/stdc++.h>
using namespace std;

int low[5100000], dfn[5100000], st[5100000];

int n, m, tim, root, dcc, top;

vector<int> g[5100000], nod[5100000];

void dfs(int u, int fa)
{
    dfn[u] = low[u] = ++tim;
    int col = 0;
    st[++top] = u;
    for (int v : g[u])
    {
        if (!dfn[v])
        {
            col++;
            dfs(v, u);
            low[u] = min(low[v], low[u]);
            if (dfn[u] <= low[v])
            {
                dcc++;
                while (st[top + 1] != v)
                {
                    nod[dcc].push_back(st[top--]);
                }
                nod[dcc].push_back(u);
            }
        }
        else if (fa != v)
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (u == root && col == 0)
    {
        nod[++dcc].push_back(u);
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1, u, v; i <= m; ++i)
    {
        cin >> u >> v;
        if (u == v) continue;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= n; ++i)
    {
        if (!dfn[i])
        {
            dfs(root = i, 0);
        }
    }
    cout << dcc << '\n';
    for (int i = 1; i <= dcc; ++i)
    {
        cout << nod[i].size() << ' ';
        for (int u : nod[i]) cout << u << ' ';
        cout << '\n';
    }
    return 0;
}

最小生成树

Kruskal
void Kruskal() {
	for (int i = 1; i <= n; ++ i) fa[i] = i;  //并查集 预处理
	sort(e + 1, e + 1 + m, cmp);              //按照 边权大小 进行排序
	for (int i = 1; i <= m; ++ i) {
		int fat_u = fat(e[i].u);
		int fat_v = fat(e[i].v);
		if (fat_u == fat_v) continue;     //判断是否 已经连边
		fa[fat_u] = fat_v;                //加边操作
		ans += e[i].w;                    //记录边权和
                //………………
		tot ++ ;
		if (tot == n - 1) break;          //树的边数为点数-1 因此跳出
	}
}
Prim
void Prim() {
    for (int i = 1; i <= n; ++ i) {
	int k = 0
	for (int j = 1; j <= n; ++ j)        //找一个与白点相连的权值最小的蓝点k
	    if(!vis[j] && mp[j] < mp[k])
		k = j;
	vis[k] = true;                       //蓝点k加入生成树,标记为白点
	for (int j = 1; j <= n; ++ j)
	    if(!vis[j] && sm[k][j] < dis[j])
		dis[j] = sm[k][j];
	}
    for (int i = 1; i <= n; ++ i)            //累加权值 
	ans += dis[i];
}
Prim & heap
 void Prim() {
    priority_queue <PAIR> q;
    int ans = 0;
    dis[1] = 0;
    q.push(make_pair(dis[1],1));
    while (!q.empty()){
        int u = q.top().second, d = q.top().first;
        q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        ans += d;
        for (int i = h[u]; i; i = e[i].nxt) {
        	int v = sm[i].v;
        	if (dis[v] > sm[i].w) {
        		dis[v] = sm[i].w;
        		 q.push(make_pair(dis[v],v));
		}
	}
    }
}

数据结构

ODT
 struct node {
    int l, r, val;
    node(int il, int ir=0, int iv=0) : l(il), r(ir), val(iv) {}
    bool operator < (const node &a) const {
        return l < a.l;
    }
};

set<node> odt;

auto split(int x)
{
    if (x > n) return odt.end();
    auto it = prev(odt.upper_bound(node(x)));
    if (it->l == x) return it;
    auto [l, r, val] = *it;
    odt.erase(it); odt.insert(node(l, x - 1, val));
    return odt.insert(node(x, r, val)).first;
}

void assign(int l, int r, int val)
{
    auto itl = perv(odt.upper_bound(node(l))), 
        itr = prev(odt.upper_bound(node(r)));

    if (itr != prev(odt.end()) && itr -> r == r && itr -> val == (itr = next(itr)) -> val)
        r = itr -> r, itr = next(itr);
    else if (itr -> val != val) itr = split(r + 1), itl = prev(odt.upper_bound(node(l)));
    else r = itr -> r, itr = nexr(itr);

    if (itl != odt.begin() && itl -> l == l && itr -> val == prev(itl) -> val)
        l = (itl = prev(itl))->l;
    else if (itl -> val != val) itl = split(l);
    else l = itl -> l;

    odt.erase(itl, itr); odt.insert(node(l, r, val)); return;
}
posted @ 2023-04-19 16:23  Ciaxin  阅读(17)  评论(0编辑  收藏  举报