GYM - 100814 C.Connecting Graph

题意:

  初始有n个点,m次操作。每次操作加一条边或者询问两个点第一次连通的时刻(若不连通输出-1)。

题解:

  用并查集维护每个点所在连通块的根。对于每次加边,暴力的更新新的根。

  每次将2个块合并时,将小的块并向大的块。这么合并使得每个点的根最多更新log2n次,并储存每次更新信息(更新时刻以及新的根)。

  对于每一次询问,二分两个点第一次连通的时刻。对于每一个二分的时刻,求的是两点的根是否相同。

  由于存储过了每个点根的更新信息,所以再用二分求出他这个时刻的根。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int t;
int n, m;
int u, v, k;
int f[N], num[N];
vector<pair<int, int> > g[N];
vector<int> c[N];
bool check(int x) {
    int l = 0, r = g[u].size()-1;
    while(l <= r) {
        int mid = l+r>>1;
        if(g[u][mid].first <= x) l = mid+1;
        else r = mid-1;
    }
    int p1 = g[u][r].second;
    l = 0, r = g[v].size()-1;
    while(l <= r) {
        int mid = l+r>>1;
        if(g[v][mid].first <= x) l = mid+1;
        else r = mid-1;
    }
    int p2 = g[v][r].second;
    if(p1==p2) return 1;
    return 0;
}
int main() {
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) {
            num[i] = 1;
            f[i] = i;
            c[i].clear();
            g[i].clear();
            c[i].push_back(i);
            g[i].push_back(make_pair(0, i));
        }
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &k, &u, &v);
            if(k&1) {
                u = f[u]; v = f[v];
                if(u!=v) {
                    if(num[u]>num[v]) swap(u, v);
                    for(int j = 0; j < num[u]; j++) {
                        c[v].push_back(c[u][j]);
                        f[c[u][j]] = v;
                        g[c[u][j]].push_back(make_pair(i, v));
                    }
                    num[v] += num[u];
                    num[u] = 0;
                    c[u].clear();
                }
            }
            else {
                int l = 0, r = i-1;
                while(l<=r) {
                    int mid = l+r>>1;
                    if(check(mid)) r = mid-1;
                    else l = mid+1;
                }
                if(check(r+1)) printf("%d\n", r+1);
                else puts("-1");
            }
        }
    }
}

原文地址:https://www.cnblogs.com/Pneuis/p/9130170.html

时间: 2024-10-21 03:20:02

GYM - 100814 C.Connecting Graph的相关文章

[LintCode] Connecting Graph

Given n nodes in a graph labeled from 1 to n. There is no edges in the graph at beginning. You need to support the following method: 1. connect(a, b), add an edge to connect node a and node b. 2.query(a, b)`, check if two nodes are connected Example

[LintCode] Connecting Graph III

Given n nodes in a graph labeled from 1 to n. There is no edges in the graph at beginning. You need to support the following method:1. connect(a, b), an edge to connect node a and node b2. query(), Returns the number of connected component in the gra

[LintCode] Surrounded Regions

Given a 2D board containing 'X' and 'O', capture all regions surrounded by 'X'. A region is captured by flipping all 'O''s into 'X''s in that surrounded region. Have you met this question in a real interview? Yes Example X X X X X O O X X X O X X O X

Gym 100801G Graph 拓扑排序

http://codeforces.com/gym/100801/attachments 用set维护一下入度为零的点,每次将当前指针和下一个指针连一条边 写博客只是为了纪念一下第一次用set,还有我逝去的4小时青春 PS.iterator在迭代器中不要xjb改 #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #

[Gym 100228] Graph of Inversions

题意 给定长度为 $n$ 的序列 $A = \left\{ a_1, a_2, ..., a_n \right\}$ . 我们定义其逆序图 $G$ : 对于 $i < j$ , $i, j$ 之间存在连边 $\Leftrightarrow a_i > a_j$ . 给定一个序列的逆序图, 求有多少个点集 $S$ , 满足 $S$ 既是独立集, 又是覆盖集. $n \le 1000$ . 分析 我们考虑探究逆序图与原序列的关系. 点集 $S$ 在逆序图中是独立集, 当且仅当在原序列中单调不降.

Gym - 100801G: Graph (贪心+set+拓扑)(好题)

题意:给定一个N点M边的有向图,叫你加最多K条边,使得最小拓扑序最大. 思路:不是那么简单的题.  参照了别人的代码,最后想通了. 贪心原则: 用两个单调队列维护, 第一个序列S1单增, 表示当前入度为0的点 ; 第二个序列S2单减,表示需要加边的点. 如果S1的最大值大于S2的最大值,则对其加边. #include<bits/stdc++.h> using namespace std; const int maxn=100010; priority_queue<int>p; pr

CodeForces Gym 100228 Graph of Inversions

题目大意 对于一个长为$N$的序列$A$,定义它所对应的逆序图: 有$N$个点组成,标号为$1...N$的无向图,对于每一组$i,j(i<j)$若存在$A_i>A_j$则在新图中就存在一条$(A_i,A_j)$的无向边. 现在给定一个$N(N\leq 1000)$个点的图,保证它是某个序列对应的逆序图,求它有多少个点集$S$,满足$\forall x\in S,y\in S$不存在边$(x,y)$,$\forall x\notin S$至少存在一条边$(x,y)$使得$y\in S$.即求图独

codeforces GYM 100114 J. Computer Network 无相图缩点+树的直径

题目链接: http://codeforces.com/gym/100114 Description The computer network of “Plunder & Flee Inc.” consists of n servers and m two-way communication links. Two servers can communicate either through a direct link, or through a chain of links, by relayi

CodeForces 505B Mr. Kitayuta&#39;s Colorful Graph

Mr. Kitayuta's Colorful Graph Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 505B Description Mr. Kitayuta has just bought an undirected graph consisting of n vertices and m edges. The