zoukankan      html  css  js  c++  java
  • 牛客多校第八场E Explorer(左开右闭线段树+可撤回并查集)题解

    题意:

    传送门

    (n)个点构成一个无向图,每条边有(L_i,R_i)表示这条边只能允许编号为(L_idots R_i)的人通过,现在问你最多有几个人能从(1)走到(n)

    思路:

    我们可以枚举每个编号,然后看看能通过这个编号的所有边能否构成一个图使得(1)走到(n),但是显然枚举点很不现实,那我们就枚举区间。
    我们用左开右闭的线段树维护区间,然后让每个节点保存能覆盖当前区间的边的编号,然后遍历这个线段树。用可撤回的并查集维护当前的图,如果(1)(n)在同一个图里,那显然当前的区间就能满足从(1)走到(n),那么就加上贡献。

    代码:

    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<cstring>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e5 + 5;
    const int INF = 0x3f3f3f3f;
    const ull seed = 131;
    const ll MOD = 1e9;
    using namespace std;
    vector<int> node[maxn << 2], vv;
    int ans, n, m;
    void build(int l, int r, int rt){
        node[rt].clear();
        if(l == r) return;
        int m = (l + r) >> 1;
        build(l, m, rt << 1);
        build(m + 1, r, rt << 1 | 1);
    }
    void update(int L, int R, int l, int r, int v, int rt){
        if(L <= l && R >= r){
            node[rt].push_back(v);
            return;
        }
        int m = (l + r) >> 1;
        if(L <= m)
            update(L, R, l, m, v, rt << 1);
        if(R > m)
            update(L, R, m + 1, r, v, rt << 1 | 1);
    }
    struct qu{
        int u, v, l, r;
    }q[maxn];
    int getid(int x){
        return lower_bound(vv.begin(), vv.end(), x) - vv.begin() + 1;
    }
    
    stack<pair<int, int> > instack;    //合并的点和其父节点暂时增加的秩
    int fa[maxn], dep[maxn];
    int _find(int x){
        return x == fa[x]? x : _find(fa[x]);
    }
    void Merge(int x, int y){
        int fx = _find(x), fy = _find(y);
        if(dep[fx] < dep[fy]){
            fa[fx] = fy;
            instack.push(make_pair(fx, 0));
        }
        else if(dep[fx] > dep[fy]){
            fa[fy] = fx;
            instack.push(make_pair(fy, 0));
        }
        else{
            fa[fx] = fy;
            dep[fy]++;
            instack.push(make_pair(fx, 1));
        }
    }
    void undo(){
        pair<int, int> s = instack.top();
        instack.pop();
        dep[fa[s.first]] -= s.second;
        fa[s.first] = s.first;
    }
    void dfs(int l, int r, int rt){
        for(int i = 0; i < node[rt].size(); i++){
            int u = q[node[rt][i]].u, v = q[node[rt][i]].v;
            Merge(u, v);
        }
        if(_find(1) == _find(n)){
            ans += vv[r] - vv[l - 1];
        }
        else if(l < r){
            int m = (l + r) >> 1;
            dfs(l, m, rt << 1);
            dfs(m + 1, r, rt << 1 | 1);
        }
        for(int i = 0; i < node[rt].size(); i++){
            undo();
        }
    }
    int main(){
        while(~scanf("%d%d", &n, &m)){
            for(int i = 1; i <= m; i++){
                scanf("%d%d%d%d", &q[i].u, &q[i].v, &q[i].l, &q[i].r);
                vv.push_back(q[i].l), vv.push_back(q[i].r + 1);
            }
            sort(vv.begin(), vv.end());
            vv.erase(unique(vv.begin(), vv.end()), vv.end());
    
            build(1, vv.size(), 1);
            for(int i = 1; i <= m; i++){
                update(getid(q[i].l), getid(q[i].r + 1) - 1, 1, vv.size(), i, 1);
            }
            for(int i = 0; i <= n; i++) fa[i] = i;
            while(!instack.empty()) instack.pop();
            ans = 0;
            dfs(1, vv.size(), 1);
            printf("%d
    ", ans);
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    LeetCode 24. Swap Nodes in Pairs (两两交换链表中的节点)
    LeetCode 1041. Robot Bounded In Circle (困于环中的机器人)
    LeetCode 1037. Valid Boomerang (有效的回旋镖)
    LeetCode 1108. Defanging an IP Address (IP 地址无效化)
    LeetCode 704. Binary Search (二分查找)
    LeetCode 744. Find Smallest Letter Greater Than Target (寻找比目标字母大的最小字母)
    LeetCode 852. Peak Index in a Mountain Array (山脉数组的峰顶索引)
    LeetCode 817. Linked List Components (链表组件)
    LeetCode 1019. Next Greater Node In Linked List (链表中的下一个更大节点)
    29. Divide Two Integers
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11391003.html
Copyright © 2011-2022 走看看