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;
    }
    
    
    
  • 相关阅读:
    从零到有模拟实现一个Set类
    node+express+mysql 实现登陆注册
    从路由原理出发,深入阅读理解react-router 4.0的源码
    linux rsyncserver文件同步
    为什么说Python是一门动态语言--Python的魅力
    python基础教程_学习笔记11:魔法方法、属性和迭代器
    list,set,map,数组间的相互转换
    TCP/IP协议族
    宿舍更换的新淋浴喷头"水温vs旋钮角度"关系的研究(曲线)
    单元測试中 Right-BICEP 和 CORRECT
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11391003.html
Copyright © 2011-2022 走看看