CF949C Data Center Maintenance Tarjan找强连通分量

题意

  • 给你\(n\)个点,每个点有一个权值\(a_x\),有\(m\)个限制条件形如\(a_x≠a_y\),现在要求你选出\(k(k>0)\)个点使其权值在模\(h\)意义下加\(1\),问最少选多少个点能让限制条件继续满足。

\(Tarjan\)求强连通分量模板题

发现对于每个限制条件,如果\(a_x+1=a_y(mod\ h)\)

那么可以给\(y\)向\(x\)连一条有向边

那么最后缩点后找到入度为\(0\)的最小\(scc\)大小即可

Codes

#include <cstdio>
#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int colors, n, m, h, a[N], be[N], size[N], de[N];

namespace Tarjan {
    int from[N << 1], to[N << 1], nxt[N << 1], head[N], e;
    int ins[N], Sta[N], low[N], dfn[N], dfn_cnt, top;

    inline void add(int x, int y) {
        to[++ e] = y; nxt[e] = head[x]; head[x] = e;
    }

    inline void dfs(int x) {
        low[x] = dfn[x] = ++ dfn_cnt, ins[Sta[++ top] = x] = 1;
        for (int i = head[x]; i; i = nxt[i]) {
            if (!dfn[to[i]]) {
                dfs(to[i]);
                low[x] = min(low[to[i]], low[x]);
            }
            else if (ins[to[i]])
                low[x] = min(dfn[to[i]], low[x]);
        }
        if (low[x] == dfn[x]) {
            ++ colors;
            do {
                ++ size[be[Sta[top]] = colors];
                ins[Sta[top]] = 0;
            }while (Sta[top --] ^ x);
        }
    }

    inline void Get_Ans() {
        for (int x = 1; x <= n; ++ x)
            for (int i = head[x]; i; i = nxt[i])
                if (be[x] ^ be[to[i]])
                    ++ de[be[to[i]]];
        int ans = 1e9, id;
        for (int i = 1; i <= colors; ++ i)
            if (!de[i] && size[i] < ans)
                ans = size[i], id = i;
        printf("%d\n", ans);
        for (int i = 1; i <= n; ++ i)
            if (be[i] == id)
                printf("%d ", i);
    }
}

int main() {
#ifdef ylsakioi
    freopen("cf949c.in", "r", stdin);
    freopen("cf949c.out", "w", stdout);
#endif

    scanf("%d%d%d", &n, &m, &h);
    for (int i = 1; i <= n; ++ i)
        scanf("%d", &a[i]);
    for (int x, y, i = 1; i <= m; ++ i) {
        scanf("%d%d", &x, &y);
        if ((a[x] + 1) % h == a[y]) Tarjan::add(y, x);
        if ((a[y] + 1) % h == a[x]) Tarjan::add(x, y);
    }

    for (int i = 1; i <= n; ++ i)
        if (!Tarjan::dfn[i])
            Tarjan::dfs(i);
    Tarjan::Get_Ans();

    return 0;
}

原文地址:https://www.cnblogs.com/brunch/p/9909343.html

时间: 2024-10-31 04:10:40

CF949C Data Center Maintenance Tarjan找强连通分量的相关文章

CF949C Data Center Maintenance(建图+强联通分量)

题意 有 n 个信息中心,第 i 个信息中心要在第 ti 个小时维护,维护期间信息不能被获得. 每个用户的数据都有两份备份,第 i 个用户的数据放在信息中心 c(i,1) 和 c(i,2). 现在要挑选一个尽量小的信息中心集合,使得将这个集合的维护时间推迟一个小时后,仍然能保证每个用户的数据在任意时刻都能获得. n≤100000 题解 对于每对 c(i,1),c(i,2),若调整 c(i,1) 后与 c(i,2) 的维护时间冲突,则连边 (c(i,1), c(i,2) ) 对于 c(i,2),c

[CF949C]Data Center Maintenance

题目大意:$n$个点,每个点有一个值$w_i$.$m$个条件,每个条件给出$x,y$,要求$w_x\not =w_y$.选择最少的点,使其值加$1$后,所有条件成立(数据保证有解). 题解:对于每个条件,若$(w_x+1)\bmod h=w_y$,连上$x->y$:若$(w_y+1)\bmod h=w_x$,连上$y->x$.一条边的含义是,若起点加一,终点也要加一.缩点,强连通分量内的点要一起加.发现答案就是找最小的没有出边的点 卡点:无 C++ Code: #include <cst

【学习整理】Tarjan:强连通分量+割点+割边

Tarjan求强连通分量 在一个有向图中,如果某两点间都有互相到达的路径,那么称中两个点强联通,如果任意两点都强联通,那么称这个图为强联通图:一个有向图的极大强联通子图称为强联通分量.   算法可以在 的时间内求出一个图的所有强联通分量. 表示进入结点 的时间 表示从 所能追溯到的栈中点的最早时间 如果某个点 已经在栈中则更新  否则对 进行回溯,并在回溯后更新  #include<iostream> #include<cstdlib> #include<cstdio>

UESTC 901 方老师抢银行 --Tarjan求强连通分量

思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个DAG(有向无环图),然后跑一遍DFS,不断加上遍历点的权值,如果到了网吧,则更新一遍答案,因为可以出去了. 求强连通分量时,如果low[u] == dfn[u],说明形成了一个新的强连通分量,且根为u.具体求强连通分量见:http://www.cnblogs.com/whatbeg/p/377642

CCF 高速公路 tarjan求强连通分量

问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的计划.看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能.如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对. 国王想知道,在大臣们给他的计划中,有多少个便利城市对. 输入

UVALive 4262——Trip Planning——————【Tarjan 求强连通分量个数】

Road Networks Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVALive 4262 Description There is a road network comprised by M<tex2html_verbatim_mark> roads and N<tex2html_verbatim_mark> cities.

hdu 1269 tarjan求强连通分量

tarjan求强连通分量的裸题复习,直接上代码: 1 #include <stack> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int N = 10001; 7 const int M = 100000; 8 int dfn[N], low[N], head[N]; 9 bool inStack[N]; 10 int n, m, e, cnt, dfs_clock

POJ 2553 The Bottom of a Graph(Tarjan,强连通分量)

解题思路: 本题要求 求出所有满足"自己可达的顶点都能到达自己"的顶点个数,并从小到大输出. 利用Tarjan算法求出强连通分量,统计每个强连通分量的出度,出度为0的强连通分量内的顶点即为所求顶点. #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cmath

Tarjan求强连通分量、求桥和割点模板

Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using namespace std; const int maxn = 1e3 + 10; const int maxm = 330000 + 10; struct EDGE{ int v, nxt; }Edge[maxm]; int Head[maxn], cnt; int DFN[maxn], LOW[maxn],