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
- https://www.cnblogs.com/Dillonh/p/11334020.html
- https://www.cnblogs.com/KirinSB/p/11391003.html
- And the master's code
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; }