zoukankan      html  css  js  c++  java
  • GYM

    题意:

      初始有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
    ", r+1);
                    else puts("-1");
                }
            }
        }    
    }
    View Code
  • 相关阅读:
    数据库设计范式
    SQL 触发器
    SQL查询上月和本月两个月的语句
    angularjs学习总结 详细教程
    指令
    重复 HTML 元素
    AngularJS 数据绑定
    AngularJS 指令.
    AngularJS 数组
    AngularJS 对象
  • 原文地址:https://www.cnblogs.com/Pneuis/p/9130170.html
Copyright © 2011-2022 走看看