题目链接: https://ac.nowcoder.com/acm/contest/888/E
题意: 给你一张无向图,每条边ui,vi的权值范围为[Li,Ri],要经过这条边的条件是你的容量要在[Li,Ri],现在问你你有多少种容量使得你可以从1走到n。
思路: 首先会想到离散化,离散l, r, 然后用线段树去维护这个区间(区间左闭,右开),每个节点存放这个容量可以通过哪些路径,最后遍历这颗树,使用可撤销并查集,来判断1是否能到n然后统计答案!
参考博客
- https://www.cnblogs.com/Dillonh/p/11334020.html
- https://www.cnblogs.com/KirinSB/p/11391003.html
- 以及师傅的代码
代码
第一次写可撤销并查集,代码有些乱,别见怪
#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;
}