题意

有 \(n\) 个点,\(m\) 条边,每条边连接 \(u \Leftrightarrow v\) 且权值为 \((a, b)\) 。

共有 \(q\) 次询问,每次询问给出 \(u, v, q_a, q_b\) 。

问是否存在一个联通块 \(S\) ,使得其中包含 \(u, v\) 且 \(S\) 中的边 \(e\) 满足 \(\max_{e \in S} a_e = q_a, \max_{e \in S} b_e = q_b\) 。

\(n, q \le 5 \times 10^4, m \le 10^5\)

题解

对于这种有两维 \(a, b\) 最大值确定的题,常常可以用分块来解决问题。

具体来说就是先把 \(a\) 从小到大排序,然后分块。

我们把每个询问挂在 \(q_a\) 被第 \(i\) 个块所有的边的 \(a_e\) 构成的区间包含的块中(如果有多个挂在最后一个)。

然后考虑把 \(i\) 之前的所有的边以及当前区间挂的询问按 \(b\) 从小到大排序即可。

然后从前往后一次处理每个操作,如果有边就加入并查集中(并查集维护连通性,以及每个联通块 \(S\) 边权 \(a,b\) 的最大值)。

如果是询问的话,暴力将当前块内合法的边(也就是两维都不超过当前询问)加入即可,然后最后记得需要把所有加入的边撤回。

这个利用可撤销并查集就行了。(按秩(深度)合并,用栈维护维护之前的状态就行了)

似乎把块调成 \(\sqrt {n \log n}\) ,可以做到 \(O(n \sqrt {n \log n})\) 的复杂度。(此处假设 \(n, m\) 同级)复杂度当然是瞎分析的啦qwq

总结

对于求两位偏序需要满足条件的题,常常可以分块然后配合可撤销数据结构来解决。

然后可以调整块大小优化复杂度?

代码

  1. #include <bits/stdc++.h>
  2. #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
  3. #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
  4. #define Set(a, v) memset(a, v, sizeof(a))
  5. #define Cpy(a, b) memcpy(a, b, sizeof(a))
  6. #define debug(x) cout << #x << ": " << (x) << endl
  7. #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
  8. using namespace std;
  9. template<typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
  10. template<typename T> inline bool chkmax(T &a, T b) { return b > a ? a = b, 1 : 0; }
  11. inline int read() {
  12. int x(0), sgn(1); char ch(getchar());
  13. for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
  14. for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
  15. return x * sgn;
  16. }
  17. void File() {
  18. #ifdef zjp_shadow
  19. freopen ("P3247.in", "r", stdin);
  20. freopen ("P3247.out", "w", stdout);
  21. #endif
  22. }
  23. const int N = 1e5 + 1e3;
  24. struct Option {
  25. int u, v, a, b, k;
  26. inline void Get(int k_ = 0) {
  27. u = read(); v = read();
  28. a = read(); b = read(); k = k_;
  29. }
  30. } E[N], Q[N];
  31. struct Cmpa {
  32. inline bool operator () (const Option &lhs,const Option &rhs) const {
  33. return lhs.a != rhs.a ? lhs.a < rhs.a : lhs.b < rhs.b;
  34. }
  35. };
  36. struct Cmpb {
  37. inline bool operator () (const Option &lhs,const Option &rhs) const {
  38. return lhs.b != rhs.b ? lhs.b < rhs.b : lhs.a < rhs.a;
  39. }
  40. };
  41. int n, m, blk, ans[N];
  42. namespace Union_Set {
  43. Option stk[N]; int top;
  44. int fa[N], height[N], maxa[N], maxb[N];
  45. int find(int x) { return fa[x] == x ? x : find(fa[x]); }
  46. Option Merge(int u, int v, int a, int b) {
  47. u = find(u); v = find(v);
  48. if (height[u] > height[v]) swap(u, v);
  49. Option tmp = (Option) {u, v, maxa[v], maxb[v], height[v]};
  50. if (height[u] == height[v]) ++ height[v]; fa[u] = v;
  51. chkmax(maxa[v], max(a, maxa[u]));
  52. chkmax(maxb[v], max(b, maxb[u])); return tmp;
  53. }
  54. void Retract() {
  55. Option cur = stk[top --];
  56. fa[cur.u] = cur.u; maxa[cur.v] = cur.a; maxb[cur.v] = cur.b; height[cur.v] = cur.k;
  57. }
  58. }
  59. Option ask[N]; int len;
  60. int id[N], Mina[N], Maxa[N], bel[N], Beg[N], End[N];
  61. int main () {
  62. File();
  63. n = read(); m = read(); blk = (int)(sqrt(n * log2(m))) * 0.6;
  64. For (i, 1, m) E[i].Get();
  65. sort(E + 1, E + m + 1, Cmpa());
  66. For (i, 1, m) {
  67. id[i] = i / blk + 1;
  68. if (id[i] != id[i - 1]) {
  69. Mina[id[i]] = Maxa[id[i]] = E[i].a;
  70. Beg[id[i]] = i; End[id[i - 1]] = i - 1;
  71. }
  72. else chkmin(Mina[id[i]], E[i].a), chkmax(Maxa[id[i]], E[i].a);
  73. }
  74. End[id[m]] = m;
  75. int q = read();
  76. For (i, 1, q) {
  77. Q[i].Get(i);
  78. Fordown (j, id[m], 1)
  79. if (Mina[j] <= Q[i].a && Q[i].a <= Maxa[j]) { bel[i] = j; break; }
  80. }
  81. using namespace Union_Set;
  82. For (i, 1, m) if (id[i] != id[i - 1]) {
  83. len = 0; For (j, 1, q) if (bel[j] == id[i]) ask[++ len] = Q[j]; if (!len) continue ;
  84. sort(E + 1, E + i, Cmpb());
  85. sort(ask + 1, ask + len + 1, Cmpb());
  86. For (j, 1, n) fa[j] = j, maxa[j] = maxb[j] = -1;
  87. int pa = 1, pb = 1;
  88. while (pa < i || pb <= len) {
  89. if ((pa < i && E[pa].b <= ask[pb].b) || pb > len) {
  90. Merge(E[pa].u, E[pa].v, E[pa].a, E[pa].b); ++ pa;
  91. } else {
  92. For (j, Beg[id[i]], End[id[i]])
  93. if (E[j].a <= ask[pb].a && E[j].b <= ask[pb].b)
  94. stk[++ top] = Merge(E[j].u, E[j].v, E[j].a, E[j].b);
  95. int rt = find(ask[pb].u);
  96. if (rt == find(ask[pb].v))
  97. ans[ask[pb].k] = maxa[rt] == ask[pb].a && maxb[rt] == ask[pb].b;
  98. while (top) Retract(); ++ pb;
  99. }
  100. }
  101. }
  102. For (i, 1, q) puts(ans[i] ? "Yes" : "No");
  103. return 0;
  104. }

LOJ #2048. 「HNOI2016」最小公倍数的更多相关文章

  1. 「HNOI2016」最小公倍数 解题报告

    「HNOI2016」最小公倍数 考虑暴力,对每个询问,处理出\(\le a,\le b\)的与询问点在一起的联通块,然后判断是否是一个联通块,且联通块\(a,b\)最大值是否满足要求. 然后很显然需要 ...

  2. loj #2051. 「HNOI2016」序列

    #2051. 「HNOI2016」序列 题目描述 给定长度为 n nn 的序列:a1,a2,⋯,an a_1, a_2, \cdots , a_na​1​​,a​2​​,⋯,a​n​​,记为 a[1: ...

  3. 「HNOI2016」最小公倍数

    链接 loj 一道阔爱的分块 题意 边权是二元组(A, B),每次询问u, v, a, b,求u到v是否存在一条简单路径,使得各边权上\(A_{max} = a, B_{max} = b\) 分析 对 ...

  4. loj2048 「HNOI2016」最小公倍数

    link 题意: 给定一张$N$个顶点$M$条边的无向图(顶点编号为$1,2,...,n$),每条边上带有权值.所有权值都可以分解成$2^a \cdot 3^b$的形式. 现在有$q$个询问,每次询问 ...

  5. loj#2049. 「HNOI2016」网络(set 树剖 暴力)

    题意 题目链接 Sol 下面的代码是\(O(nlog^3n)\)的暴力. 因为从一个点向上只会跳\(logn\)次,所以可以暴力的把未经过的处理出来然后每个点开个multiset维护最大值 #incl ...

  6. LOJ#2052. 「HNOI2016」矿区(平面图转对偶图)

    题面 传送门 题解 总算会平面图转对偶图了-- 首先我们把无向边拆成两条单向边,这样的话每条边都属于一个面.然后把以每一个点为起点的边按极角排序,那么对于一条边\((u,v)\),我们在所有以\(v\ ...

  7. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  8. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  9. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

随机推荐

  1. 原生jS之-去掉字符串开头和结尾的空字符

    怎么解决这个问题?? 思路就是我们利用正则匹配到所谓的空格,然后替换为空字符,我们要用到的是str的replace API 代码如下: <!DOCTYPE html> <html l ...

  2. Day1 初步认识Python

    天气有点阴晴不定~ (截图来自----------金角大王) 1.学习了计算机概论(CPU/Memory/Disk,memory的存在是为了解决信息传输产生的时延) CPU:精简指令集(RISC)-- ...

  3. 2019省赛训练组队赛3.31周四-17fj

    https://vjudge.net/contest/289558#overview A - Frog Therearex frogs and y chicken in a garden. Kim f ...

  4. clone内容包含select2

    如果克隆的内容包含select2,克隆之后要先删除select之后自动生成的span,再对select2进行初始化,生成新的元素.

  5. flutter图片铺满父框

    正常我们需要显示一张图片,会用到Image这个控件. 打个比方,我们加载一张本地的图片, 先看一下这个Image.asset的源码: Image.asset(String name, { Key ke ...

  6. php redis常用方法代码例子

    1,connect 描述:实例连接到一个Redis.参数:host: string,port: int返回值:BOOL 成功返回:TRUE;失败返回:FALSE 示例: <?php $redis ...

  7. SpringMVC 重定向到其他系统的页面的两种方式

    //测试重定向到另外的一个系统 @RequestMapping("/tttt") public void testRed(HttpServletResponse response) ...

  8. css伪元素之before和after

    css里面的伪元素主要是用来给选择器设置特殊效果.根据常用性,记录before和after. “:before”伪元素用来在元素的内容前面添加新的元素.比如标题前面会有一个小方块,就可以通过‘ :be ...

  9. 安装mysql zip5.6版--安裝

    第一步当然是下载了,我下载的是压缩包形式的安装包,这种直接解压就可以了,地址是:https://dev.mysql.com/downloads/file/?id=468784 第二步就是解压了,解压到 ...

  10. HJ212 CRC 16 (C#)

    算法 CRC16 校验寄存器赋值为 0xFFFF: 取被校验串的第一个字节赋值给临时寄存器: 临时寄存器与 CRC16 校验寄存器的高位字节进行"异或"运算,赋值给 CRC16 校 ...