ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2019牛客暑期多校训练营(第八场场)_E题 Explorer(线段树+可撤销并查集)

2019-09-06 16:01:19  阅读:251  来源: 互联网

标签:em tmp ve int 查集 多校 num root Explorer


题目链接: https://ac.nowcoder.com/acm/contest/888/E

题意: 给你一张无向图,每条边ui,vi的权值范围为[Li,Ri],要经过这条边的条件是你的容量要在[Li,Ri],现在问你你有多少种容量使得你可以从1走到n。

思路: 首先会想到离散化,离散l, r, 然后用线段树去维护这个区间(区间左闭,右开),每个节点存放这个容量可以通过哪些路径,最后遍历这颗树,使用可撤销并查集,来判断1是否能到n然后统计答案!

参考博客

代码

第一次写可撤销并查集,代码有些乱,别见怪

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
vector<pair<int, int> > node[MAXN<<2];
vector<int> ve;
int ans, n, m, tot;
int vis[MAXN], num[MAXN];
struct edge
{
    int u;
    int v;
    int l;
    int r;
}em[MAXN];

struct info
{
    int u;
    int v;
    int w;
};
inline void init()
{
    ve.clear();
}
inline void Build(int root, int l, int r)
{
    node[root].clear();
    if(l == r) return ;

    int mid = (l + r) >> 1;

    Build(root<<1, l, mid);
    Build(root<<1|1, mid + 1, r);
}

inline void updata(int root, int l, int r, int L, int R, pair<int, int> add)
{
    if(L <= l && r <= R){
        node[root].push_back(add);
        return ;
    }

    int mid = (l + r) >> 1;

    if(L <= mid){
        updata(root<<1, l, mid, L, R, add);
    }
    if(R > mid){
        updata(root<<1|1, mid + 1, r, L, R, add);
    }
}

inline int getID(int x)
{
    return (lower_bound(ve.begin(), ve.end(), x) - ve.begin() +  1);
}

inline int findx(int x)
{
    int r = x;
    while(r != vis[r]){
        r = vis[r];
    }

    return r;
}

inline info marge(int a, int b)
{
    int x = findx(a), y = findx(b);

    if(x == y) return {-1, -1, -1};
    if(num[x] > num[y]) swap(x, y);

    info tmp = {x, y, num[y]};

    vis[x] = y;
    num[y] = max(num[y] + 1, num[x] + 1);

    return tmp;
}

void dfs(int root, int l, int r)
{
    stack<info> st;
    int len = node[root].size();
    //并查集
    for(int i = 0; i < len; i++){
        info tmp = marge(node[root][i].first, node[root][i].second);
        if(tmp.u != -1) st.push(tmp);
    }
    //可以从1到n
    if(findx(1) == findx(n)){
        ans += ve[r] - ve[l - 1];
    }
    else if(l != r){
        int mid = (l + r) >> 1;
        dfs(root<<1, l, mid);
        dfs(root<<1|1, mid + 1, r);
    }
    //撤销并查集
    while(st.size()){
        info tmp = st.top();
        st.pop();
        vis[tmp.u] = tmp.u;
        vis[tmp.v] = tmp.v;
        num[tmp.v] = tmp.w;
    }
}
int main()
{
    ios::sync_with_stdio(false);

    while(cin >> n >> m){
        init();
        for(int i = 1; i <= m; i++){
            cin >> em[i].u >> em[i].v >> em[i].l >> em[i].r;
            em[i].r += 1;
            ve.push_back(em[i].l);
            ve.push_back(em[i].r);
        }
        //离散化
        sort(ve.begin(), ve.end());
        ve.erase(unique(ve.begin(), ve.end()), ve.end());
        tot = ve.size();

        Build(1, 1, tot);

        for(int i = 1; i <= m; i++){
            //左闭 右开
            updata(1, 1, tot, getID(em[i].l), getID(em[i].r) - 1, make_pair(em[i].u, em[i].v));
        }
        ans = 0;
        //初始化
        for(int i = 1; i <= n; i++){
            vis[i] = i;
            num[i] = 0;
        }
        dfs(1, 1, tot);
        cout << ans << endl;
    }
    return 0;
}

标签:em,tmp,ve,int,查集,多校,num,root,Explorer
来源: https://blog.csdn.net/HKer_YM/article/details/100580780

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有