题意

n个点,m条边,u,v,l,r表示点u到点v有一条边,且只有编号为\([l,r]\)的人能通过,问从点1到点n有哪些编号的人能通过

题解

先对\(l,r\)离散化,用第七场找中位数那题同样的形式建树,每个叶子节点表示的都是一个区间,树上每个节点维护的是,包含这个区间的边有哪些,可以用vector存下来,接着是查询哪些叶子节点可以作为答案,像线段树build一样左右一直递归下去,每递归一次都把这个节点存的边用并查集合并,思考一下就能知道,按build的方式递归下去,到叶子节点x,一定能途径所有包含叶子节点x所表示的区间的边,且不会途径不包含x表示的区间的边,这样到叶子节点是就把包含该叶子节点区间的边全部合并,此时查询点1和点n是否在一起,若在一起就可以把该叶子节点区间计入答案,查询的时候每层递归结束都要撤销并查集合并操作,以免影响递归其他叶子节点的时候影响答案,用启发式并查集合并就能撤销了

代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int mx = 2e5+5;
vector <int> vv;
vector <int> edge[mx<<2];
int u[mx], v[mx], l[mx], r[mx], fa[mx], sz[mx], top = 0;
int n, m;
pair <int, int> st[mx];
int getid(int x) {
return lower_bound(vv.begin(), vv.end(), x) - vv.begin() + 1;
} int find(int x) {
return fa[x] == x ? x : find(fa[x]);
} void merge(int u, int v) {
int fau = find(u);
int fav = find(v);
if (fau == fav) return;
if (sz[fau] > sz[fav]) swap(fau, fav);
fa[fau] = fav;
st[top++] = {fau, sz[fau]};
if (sz[fau] == sz[fav]) {
st[top++] = {fav, sz[fav]};
sz[fav]++;
}
} void update(int L, int R, int id, int l, int r, int rt) {
if (L <= l && r <= R) {
edge[rt].push_back(id);
return;
}
int mid = (l + r) / 2;
if (L <= mid) update(L, R, id, l, mid, rt<<1);
if (mid < R) update(L, R, id, mid+1, r, rt<<1|1);
} void cancel(int pre) {
while (top > pre) {
fa[st[top-1].first] = st[top-1].first;
sz[st[top-1].first] = st[top-1].second;
top--;
}
} void query(int l, int r, int rt, int &ans) {
int pre = top;
for (int i = 0; i < edge[rt].size(); i++) {
int id = edge[rt][i];
merge(u[id], v[id]);
}
if (l == r) {
if (find(1) == find(n)) ans += vv[r]-vv[l-1];
cancel(pre);
return;
}
int mid = (l + r) / 2;
query(l, mid, rt<<1, ans);
query(mid+1, r, rt<<1|1, ans);
cancel(pre);
} int main() {
for (int i = 0; i < mx; i++) {
fa[i] = i;
sz[i] = 1;
}
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d%d", &u[i], &v[i], &l[i], &r[i]);
r[i]++;
vv.push_back(l[i]);
vv.push_back(r[i]);
}
sort(vv.begin(), vv.end());
vv.push_back(vv[vv.size()-1] + 1);
vv.erase(unique(vv.begin(), vv.end()), vv.end()); for (int i = 1; i <= m; i++) {
update(getid(l[i]), getid(r[i])-1, i, 1, vv.size()-1, 1);
}
int ans = 0;
query(1, vv.size()-1, 1, ans);
printf("%d\n", ans);
return 0;
}

最新文章

  1. Windows Live Writer代码插件整理
  2. IOS培训还值得么
  3. solr入门命令
  4. ArcGIS10.2下调试10.1的程序
  5. RMAN命令
  6. 我的android学习经历30
  7. :判断101-200之间有多少个素数,并输出所有素数。 程序分析:判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除, 则表明此数不是素数,反之是素数。
  8. UVa 10361 Automatic Poetry
  9. iOS开发中.pch 文件的使用及其相关工程设置
  10. YII 框架使用之——创建应用
  11. object- c 字符串操作
  12. View的工作原理(一)——Measure
  13. [iOS]C语言知识点系列视频
  14. 1.3. 创建 Grocery Dude 项目(Core Data 应用程序实践指南)
  15. LuaHotUpdate原理
  16. Hessian探究(一)Hessian入门示例
  17. dubbo源码分析11——服务暴露2_doExport()方法分析
  18. Spring学习笔记2:Spring HelloWorld
  19. Ubuntu 更新系统版本以及查看当前系统版本的命令
  20. 力扣(LeetCode)226. 翻转二叉树

热门文章

  1. 【pip】brew install pip 问题
  2. 用python twilio模块实现发手机短信的功能
  3. hdoj 3732 Ahui Writes Word (多重背包)
  4. drf初体验
  5. maven 打包并导出 lib 第三方jar
  6. Linux下安装jupyter
  7. 08_代码块丶继承和final
  8. Ubuntu 16.04 硬盘安装
  9. java多线程中wait/notify/sleep/join/yield方法以及多线程的六种状态
  10. F#周报2019年第32期