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;
    }
    
    
    
  • 相关阅读:
    什么是webview
    juqery.fn.extend和jquery.extend
    LeetCode
    5. Longest Palindromic Substring
    42. Trapping Rain Water
    11. Container With Most Water
    621. Task Scheduler
    49. Group Anagrams
    739. Daily Temperatures
    3. Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11391003.html
Copyright © 2011-2022 走看看