2009 Niuke Summer Multi-School Training Camp (Game 8)_E Question Explorer (Line Segment Tree + Revocable and Collection)

Posted by gammaman on Tue, 01 Oct 2019 17:20:07 +0200

Topic link: https://ac.nowcoder.com/acm/contest/888/E

Title: Give you an undirected graph, each edge ui,vi weight range [Li,Ri], to go through this side of the condition is your capacity in [Li,Ri], now ask you how many kinds of capacity you have so that you can go from 1 to n.

Idea: First, we think of discretization, discretization l, r, and then use segment tree to maintain the interval (left closed, right open), which paths can each node store this capacity through, and finally traverse the tree, using revocable and search, to determine whether 1 can reach n and then statistics the answer!

Reference blog

Code

Write revocable and collect for the first time. The code is messy. Don't worry.

#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;      //Number of points pointed
};
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();
    //Union checking set
    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);
    }
    //From 1 to 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);
    }
    //Revoke and search
    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);
        }
        //Discretization
        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++){
            //Close left and open right
            updata(1, 1, tot, getID(em[i].l), getID(em[i].r) - 1, make_pair(em[i].u, em[i].v));
        }
        ans = 0;
        //Initialization
        for(int i = 1; i <= n; i++){
            vis[i] = i;
            num[i] = 0; // The number of points pointed to this point is 0.
        }
        dfs(1, 1, tot);
        cout << ans << endl;
    }
    return 0;
}

Topics: iOS