Codeforces 455C Civilization(并查集+dfs)

题目链接:Codeforces 455C Civilization

题目大意:给定N,M和Q,N表示有N个城市,M条已经修好的路,修好的路是不能改变的,然后是Q次操作,操作分为两种,一种是查询城市x所在的联通集合中,最长的路为多长。二是连接两个联通集合,采用联通之后最长路最短的方案。

解题思路:因为一开时的图是不可以改变的,所以一开始用dfs处理出各个联通集合,并且记录住最大值,然后就是Q次操作,用并查集维护,注意因为联通的时候要采用最长路径最短的方案,所以s的转移方程变为s = max(s, (s+1)/2 + (s0+1)/2 + 1)

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;
const int maxn = 3 * 1e5 + 5;
int N, M, Q, f[maxn], s[maxn];
int root, ans, rec;
vector<int> g[maxn];

int getfar(int x) {
    return f[x] == x ? x : f[x] = getfar(f[x]);
}

void link (int u, int v) {
    int x = getfar(u);
    int y = getfar(v);

    if (x == y)
        return;

    if (s[x] < s[y])
        swap(s[x], s[y]);

    f[y] = x;
    s[x] = max(s[x], (s[x] + 1) / 2 + (s[y] + 1) / 2 + 1);
}

void dfs (int u, int p, int d) {
    f[u] = root;

    if (d > ans) {
        ans = d;
        rec = u;
    }

    for (int i = 0; i < g[u].size(); i++) {
        if (g[u][i] != p)
            dfs(g[u][i], u, d+1);
    }
}

int main () {
    int type, u, v;

    scanf("%d%d%d", &N, &M, &Q);
    for (int i = 1; i <= N; i++) {
        f[i] = i;
        g[i].clear();
    }

    for (int i = 0; i < M; i++) {
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }

    for (int i = 1; i <= N; i++) {
        if (f[i] == i) {
            root = rec = i;
            ans = -1;
            dfs(i, 0, 0);

            ans = -1;
            dfs(rec, 0, 0);
            s[i] = ans;
        }
    }

    for (int i = 0; i < Q; i++) {
        scanf("%d", &type);
        if (type == 1) {
            scanf("%d", &u);
            v = getfar(u);
            printf("%d\n", s[v]);
        } else {
            scanf("%d%d", &u, &v);
            link(u, v);
        }
    }
    return 0;
}

Codeforces 455C Civilization(并查集+dfs)

时间: 2024-08-09 10:44:49

Codeforces 455C Civilization(并查集+dfs)的相关文章

BZOJ 3562: [SHOI2014]神奇化合物 并查集+dfs

点击打开链接 注意到20w条边,但是询问只有1w,所以有很多边是从头到尾不变的. 首先离线处理,将从未删除的边缩点,缩点后的图的点数不会超过2w,对于每一次add或者delete,直接dfs看是否能从a走到b,然后维护一个ans. 数据不强,不然这种复杂度起码要跑10s.. #include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> using namespace st

Codeforces 437D 贪心+并查集

这个题目让我想起了上次在湘潭赛的那道跪死了的题.也是最值问题,这个也是,有n个动物园 每个都有权值 然后被m条路径相连接,保证图是连通的,然后求所有的p[i][j]之和.i,j为任意两个zoo,pij就为i到j路上遇到的包括i j在内的最小权值的zoo 然后我就焦头烂额了一下,这个明显就是看某个最小值为最后的结果发挥了多少次作用,但这个是图,要知道某个节点到底给多少条路径贡献出了最小值,还真是有点没头绪(在已知的复杂度一看 最多只能用nlogn的),最后是看了解答才知道的 用并查集来解决某个最小

1021. Deepest Root (25) 并查集&amp;&amp;DFS

1021. Deepest Root (25) 时间限制 1500 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root t

CCF 201512-4 送货 (并查集+DFS,欧拉路)

问题描述 为了增加公司收入,F公司新开设了物流业务.由于F公司在业界的良好口碑,物流业务一开通即受到了消费者的欢迎,物流业务马上遍及了城市的每条街道.然而,F公司现在只安排了小明一个人负责所有街道的服务. 任务虽然繁重,但是小明有足够的信心,他拿到了城市的地图,准备研究最好的方案.城市中有n个交叉路口,m条街道连接在这些交叉路口之间,每条街道的 首尾都正好连接着一个交叉路口.除开街道的首尾端点,街道不会在其他位置与其他街道相交.每个交叉路口都至少连接着一条街道,有的交叉路口可能只连接着一 条或两

Deepest Root (并查集+DFS树的深度)

A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root. Input Specification: E

2018 计蒜之道复赛 贝壳找房魔法师顾问(并查集+dfs判环)

贝壳找房在遥远的传奇境外,找到了一个强大的魔法师顾问.他有 22 串数量相同的法力水晶,每个法力水晶可能有不同的颜色.为了方便起见,可以将每串法力水晶视为一个长度不大于 10^5105,字符集不大于 10^5105 的字符串.现在魔法师想要通过一系列魔法使得这两个字符串相同.每种魔法形如 (u,\ v),\ u,\ v \le 10^5(u, v), u, v≤105,可以将一个字符 uu改成一个字符 vv,并且可以使用无限次.出于种种原因,魔法师会强行指定这两个串能否进行修改. 若失败输出 -

F2 - Spanning Tree with One Fixed Degree - 并查集+DFS

这道题还是非常有意思的,题意很简单,就是给定一个图,和图上的双向边,要求1号节点的度(连接边的条数)等于K,求这棵树的生成树. 我们首先要解决,如何让1号节点的度时为k的呢???而且求的是生成树,意思是不是所有边都会选择.那么我们如何选择才能保证1号节点有K个度呢???这里就要考虑联通分量的问题了,我们刨除1号点,那么联通分量的个数,就是我们让图联通的最小个数,因此我们需要用并查集,把点分在不同的联通块内部. 再考虑我们每个联通块,至少需要1条连接1号点的边.不够K再添加连接1号点的边. 然后考

Codeforces 200A Cinema 并查集 + 思维 (看题解)

Cinema 感觉这个题好神啊... 首先如果 n 比 m 大, 我们先旋转90度. 我们要加入一个(x, y)的时候, 我们枚举答案所在的行离 x 的距离 g , 然后对于x + g 行来说 我们找到(x + g, y)左边的第一个和右边的第一个未被占的位置,更新答案, 如果 g > 答案 退出. 左边和右边第一个未被占的可以用并查集维护, 把连续占了的并成一个联通块, 维护最小值和最大值. 对于 2000 * 2000的图来说, 对于每一次, 最多sqrt( n )就能找到答案, 因为最坏情

CodeForces - 1253D(并查集)

题意 https://vjudge.net/problem/CodeForces-1253D 一个无向图,对于任意l,r,如果l到r有路径,那么l到m也有路径(l<m<r),问最少加多少条边,使得上述条件成立. 思路 先用并查集缩成若干个连通块,顺带把每个连通块的最大值求出来,然后我们从1到n开始遍历每个点,记录当前点所在连通块的最大值,然后如果i小于最大值而且和i-1不在一个连通块内,就合并这两个连通块.计算需要合并的次数即可. 代码 #include<bits/stdc++.h>