hdu 4677 并查集+分块算法 好题 (2013多校联合)
2013-08-30 23:01
316 查看
题意:点数n(n <= 30000), 边数(m <= 90000)的图,询问 q(1<=q<=30000)。
对于每个询问(l, r),去掉(l,r)区间以外的所有点和其相关联的边,问剩下来的图的联通块的个数。
思路:分块+并查集
分块算法入门:http://blog.csdn.net/auto_ac/article/details/10050589
这题很容易想到分块, 难点是并查集的处理。
对询问离线分块排序以后,我们对 左端点在相同块号内的询问 一起处理。这些询问的右断点是递增的,
左端点在某个块内,我们对每个询问分成2个区域分别进行并查集处理,区域1:左端点所在的块的区域(并查集tp)
(点的个数sqrt(n))。区域2:除区域1以外的其它询问点(并查集f)。由于右断点是递增的,区域2很容易用一个并查集处理。区域1对于每个询问,都重新处理一遍并查集。最后关键就是两个并查集的合并,由于并查集不能进行删除操作,我们需要做的是
利用并查集f里面的信息而不破坏它,并且复杂度要符合题意。我们可以在维护并查集tp的同时让这两个并查集合并,即在并查集f中把我当前需要的点搬到并查集tp里面,而没有必要把并查集f全部搬过来,而且这样做复杂度也不符合要求,用一个vis数组就可以做到
在实际处理的时候 并查集tp能处理到的点是整个询问的区域内的点。
具体看代码吧。
对于每个询问(l, r),去掉(l,r)区间以外的所有点和其相关联的边,问剩下来的图的联通块的个数。
思路:分块+并查集
分块算法入门:http://blog.csdn.net/auto_ac/article/details/10050589
这题很容易想到分块, 难点是并查集的处理。
对询问离线分块排序以后,我们对 左端点在相同块号内的询问 一起处理。这些询问的右断点是递增的,
左端点在某个块内,我们对每个询问分成2个区域分别进行并查集处理,区域1:左端点所在的块的区域(并查集tp)
(点的个数sqrt(n))。区域2:除区域1以外的其它询问点(并查集f)。由于右断点是递增的,区域2很容易用一个并查集处理。区域1对于每个询问,都重新处理一遍并查集。最后关键就是两个并查集的合并,由于并查集不能进行删除操作,我们需要做的是
利用并查集f里面的信息而不破坏它,并且复杂度要符合题意。我们可以在维护并查集tp的同时让这两个并查集合并,即在并查集f中把我当前需要的点搬到并查集tp里面,而没有必要把并查集f全部搬过来,而且这样做复杂度也不符合要求,用一个vis数组就可以做到
在实际处理的时候 并查集tp能处理到的点是整个询问的区域内的点。
具体看代码吧。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> using namespace std; #define pb push_back const int maxn = 30004; vector<int> edge[maxn]; int n, m; int bsize; struct node { int l, r, b, no;//b块号,no询问编号 inline void in(int i) { scanf("%d%d", &l, &r); b = l/ bsize; no = i; } bool operator <(const node &t) const { //先按左端点所在的块号排,再按右端点排 if (b == t.b) return r < t.r; return b < t.b; } } q[maxn]; int cnt, sum; //cnt: 右边并查集f的联通块个数, sum 左边并查集tp的联通块个数 int f[maxn], tp[maxn]; int vis[maxn]; //vis[x]表示最后一次用到x的询问是哪一个,可以记录当前询问用没有把点x放过 处理左边的并查集tp中 //R: 处理区域2, 即右边区域的并查集 int Rfind(int x) { return x == f[x] ? x : f[x] = Rfind(f[x]); } void Rmerge(int x, int y) { int rx = Rfind(x), ry = Rfind(y); if (rx == ry) return; f[rx] = ry; cnt--; } //L: 处理区域1, 即左边区域的并查集 int cur;//当前的询问号 int Lfind(int x) { if (vis[x] != cur) {//判断点x是否加入 处理左边的并查集tp, 没加入就加进来,更新vis vis[x] = cur; tp[x] = f[x]; } return x == tp[x] ? x : tp[x] = Lfind(tp[x]) ; } void Lmerge(int x, int y) { int rx = Lfind(x); int ry = Lfind(y); if (rx == ry) return; tp[rx] = ry; sum--; } int ans[maxn]; int R, B; //在当前询问之前的询问的右端点和块号 int work(int l, int r, int b) { int z = bsize * (b+1)-1, i, j; //z是左右边区间的分界点,z点属于左边 if (B != b) { //新的一个块的第一个询问 R = z; B = b; cnt = 0; for (i = z-bsize+1; i <= n; i++) //只要对f初始化,tp不用初始化(因为用vis更新的缘故)。 f[i] = i; } //更新右边并查集 for (i = max(R, z)+1; i <= r; i++) { cnt++; for (j = 0; j <(int) edge[i].size(); j++) { int v = edge[i][j]; if (v > r || v <= z) continue; Rmerge(i, v); } } //更新左边并查集 sum = 0; for (i = l; i <= min(r, z); i++) { sum++; for (j = 0; j <(int) edge[i].size(); j++) { int v = edge[i][j]; if (v > r || v < l) continue; Lmerge(i, v); } } R = r; return sum+cnt; } void solve() { int i, j, k; R = B = -1; for (i = 0; i < m; i++) { j = i; while (j < m && q[j].b == q[i].b) j++; //对于左端点在一个块内的询问一起处理 for (k = i; k < j; k++) { cur = k; ans[q[k].no] = work(q[k].l, q[k].r, q[k].b); } i = j - 1; } } int main() { int i, cas, ca = 1; scanf("%d", &cas); while (cas--) { scanf("%d%d", &n, &m); for(i = 1; i <= n; i++) edge[i].clear(); while (m--) { int x, y; scanf("%d%d", &x, &y); edge[x].pb(y); edge[y].pb(x); } bsize = sqrt(n + 0.5); scanf("%d", &m); for (i = 0; i < m; i++) q[i].in(i); sort(q, q + m); memset(vis, -1, sizeof(vis)); solve(); printf("Case #%d:\n", ca++); for(i = 0; i < m; i++) printf("%d\n", ans[i]); } return 0; }
相关文章推荐
- hdu 4677 并查集+分块算法 好题 (2013多校联合)
- hdu 4619 warm up 2 并查集或搜索都可以做出来的题 2013多校联合训练第二场
- hdu 4677 并查集合并(两个相邻区间并查集的合并)+分块算法 好题
- HDU 4637 Rain on your Fat brother 线段与半圆和线段交 简单题 (2013多校联合)
- HDU 4643 GSM 简单计算几何 (2013多校联合)
- hdu 4699 2个栈维护 or 伸展树 (2013多校联合)
- 2013 多校联合 I I-number(hdu 4608)
- 2013 多校联合2 D Vases and Flowers (hdu 4614)
- 2013多校联合4 1010 K-string (hdu 4641)
- HDU 4686 Arc of Dream (2013多校联合9 1001)
- HDU 5326 Work 并查集 (2015 Multi-University Training Contest 3 2015多校联合)
- HDU 4632 2013多校联合第4场 A - Palindrome subsequence
- hdu 4313 Matrix 并查集 多校联合赛(二) 第四题
- 2013多校联合8 String (hdu 4681)
- 2013 多校联合 H Park Visit (hdu 4607)
- 2013多校联合4 1001 Palindrome subsequence(hdu 4632)
- 2013 多校联合2 D Vases and Flowers (hdu 4614)
- hdu 4661 Message Passing 树形dp (2013多校联合)
- 2013多校联合2 I Warm up 2(hdu 4619)
- hdu 4607 park visit 2013多校联合训练第一场