Input

Output

Sample Input

4 5
1 2
2 3
3 4
4 1
2 4
3
1 5
2 2 3
2 1 2

Sample Output

Connected
Disconnected
Connected

Hint

N<=100000 M<=200000 K<=100000


  题目大意 给出一个有n个节点和m条边的图,然后有k个询问,每个询问是删掉一些边,然后判断图是否连通,询问之间互相独立。

  连通性问题通常的做法是并查集,然而并查集不支持删边,但是可以撤销上次操作,所以只能考虑把一条一条边加入并查集,为了高效的确定边是否存在,可以用一个时间戳(其实就是确定某条边在询问时是否存在)。因为存在的时间段是连续的,所以呢就用一个线段树,每个点开一个vector,记录恰好存在时间段为当前区间的的边有哪些。

  接着开始遍历整棵树,每到一个点就把它存的边一一塞进并查集

  1)如果不是叶节点,然后访问左右子树,访问完后O(1)撤销这个点加入的所有边

  2)如果是叶节点,就随便找个点的最高级father(就是f[father] = father)看下它的size是否为n(然后一个操作就"水"完了)

  因为并查集要支持撤销,所以不能压缩路径了,只能按秩合并(把小的合并到大的中)。

  注意题目输入中的数据范围是错的(然后我就RE了一次)

Code

 /**
* bzoj
* Problem#3237
* Accepted
* Time:19508ms
* Memory:72656k
*/
#include <iostream>
#include <cstdio>
#include <ctime>
#include <cmath>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <stack>
#ifndef WIN32
#define Auto "%lld"
#else
#define Auto "%I64d"
#endif
using namespace std;
typedef bool boolean;
const signed int inf = (signed)((1u << ) - );
const signed long long llf = (signed long long)((1ull << ) - );
const double eps = 1e-;
const int binary_limit = ;
#define smin(a, b) a = min(a, b)
#define smax(a, b) a = max(a, b)
#define max3(a, b, c) max(a, max(b, c))
#define min3(a, b, c) min(a, min(b, c))
template<typename T>
inline boolean readInteger(T& u){
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-' && x != -);
if(x == -) {
ungetc(x, stdin);
return false;
}
if(x == '-'){
x = getchar();
aFlag = -;
}
for(u = x - ''; isdigit((x = getchar())); u = (u * ) + x - '');
ungetc(x, stdin);
u *= aFlag;
return true;
} typedef class SegTreeNode {
public:
vector< pair<int, int> > e;
SegTreeNode *l, *r; SegTreeNode() { }
SegTreeNode(SegTreeNode* l, SegTreeNode* r):l(l), r(r) { }
}SegTreeNode; SegTreeNode pool[];
SegTreeNode *top = pool;
SegTreeNode null = SegTreeNode(&null, &null); inline SegTreeNode* newnode() {
*top = SegTreeNode(&null, &null);
return top++;
} typedef class union_found {
public:
int n;
SegTreeNode* root;
int* f;
int* s;
stack< pair<int, int> > trace;
stack< pair<int, int> > ss;
union_found():root(NULL) { }
union_found(int n):root(&null), n(n) {
f = new int[(n + )];
s = new int[(n + )];
fill(s, s + n + , );
for(int i = ; i <= n; i++)
f[i] = i;
} int find(int x) {
return (f[x] == x) ? (x) : (find(f[x]));
} inline void unit(int fa, int so) {
int ffa = find(fa);
int fso = find(so);
if(ffa == fso) trace.push(pair<int, int>(, ));
else {
if(s[ffa] < s[fso])
swap(ffa, fso);
trace.push(pair<int, int>(fso, f[fso]));
ss.push(pair<int, int>(ffa, s[ffa]));
s[ffa] += s[fso];
f[fso] = ffa;
}
} inline void undo() {
pair<int, int> p = trace.top();
pair<int, int> sp = ss.top();
trace.pop();
if(p.first == ) return;
f[p.first] = p.second;
s[sp.first] = sp.second;
ss.pop();
} void update(SegTreeNode*& node, int l, int r, int ql, int qr, pair<int, int> &val) {
if(node == &null) node = newnode();
if(l == ql && r == qr) {
// printf("Update at segment [%d, %d] with the edge (%d, %d)\n", l, r, val.first, val.second);
node->e.push_back(val);
return;
}
int mid = (l + r) >> ;
if(qr <= mid) update(node->l, l, mid, ql, qr, val);
else if(ql > mid) update(node->r, mid + , r, ql, qr, val);
else {
update(node->l, l, mid, ql, mid, val);
update(node->r, mid + , r, mid + , qr, val);
}
} void query(SegTreeNode* node, int l, int r, boolean *res) {
pair<int, int> p;
for(int i = ; i < (signed)node->e.size(); i++) {
p = node->e[i];
unit(p.first, p.second);
// printf("Connect %d and %d\n", p.first, p.second);
}
if(l == r) {
res[l] = (s[find()] == n);
} else {
int mid = (l + r) >> ;
query(node->l, l, mid, res);
query(node->r, mid + , r, res);
}
for(int i = ; i < (signed)node->e.size(); i++)
undo();
}
}union_found; int n, m, q;
pair<int, int> *es;
vector<int> *exists;
union_found uf; inline void init() {
readInteger(n);
readInteger(m);
es = new pair<int, int>[(m + )];
for(int i = ; i <= m; i++) {
readInteger(es[i].first);
readInteger(es[i].second);
}
exists = new vector<int>[(m + )];
readInteger(q);
for(int i = , c, x; i <= q; i++) {
readInteger(c);
while(c--) {
readInteger(x);
exists[x].push_back(i);
}
}
} inline void mktree() {
uf = union_found(n);
for(int i = ; i <= m; i++) {
exists[i].push_back(q + );
for(int j = , last = ; j < (signed)exists[i].size(); j++) {
if(last == exists[i][j])
last++;
else {
// cout << exists[i][j] << endl;
uf.update(uf.root, , q, last, exists[i][j] - , es[i]);
last = exists[i][j] + ;
}
}
}
} boolean *res;
inline void solve() {
res = new boolean[(q + )];
uf.query(uf.root, , q, res);
for(int i = ; i <= q; i++)
puts((res[i]) ? ("Connected") : ("Disconnected"));
} int main() {
init();
mktree();
solve();
return ;
}

bzoj 3237 连通图 - 并查集 - 线段树的更多相关文章

  1. BZOJ 3910 并查集+线段树合并

    思路: 1. 并查集+线段树合并 记得f[LCA]==LCA的时候 f[LCA]=fa[LCA] 2.LCT(并不会写啊...) //By SiriusRen #include <cstdio& ...

  2. UVA1455 - Kingdom(并查集 + 线段树)

    UVA1455 - Kingdom(并查集 + 线段树) 题目链接 题目大意:一个平面内,给你n个整数点,两种类型的操作:road x y 把city x 和city y连接起来,line fnum ...

  3. 并查集&线段树&树状数组&排序二叉树

    超级无敌巨牛逼并查集(带权并查集)https://vjudge.net/problem/UVALive-4487 带删点的加权并查集 https://vjudge.net/problem/UVA-11 ...

  4. 【Codeforces576E_CF576E】Painting Edges(可撤销并查集+线段树分治)

    题目 CF576E 分析: 从前天早上肝到明天早上qwq其实颓了一上午MC ,自己瞎yy然后1A,写篇博客庆祝一下. 首先做这题之前推荐一道很相似的题:[BZOJ4025]二分图(可撤销并查集+线段树 ...

  5. bzoj 2733 永无乡 - 并查集 - 线段树

    永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛. ...

  6. BZOJ 3319 黑白树 并查集+线段树

    这这这这这这什么毒瘤题!!!!!!!!!!!!!!!!!!!!!!!!!!!! 卡LCT(优秀的LCT由于是均摊本身就带着2,3的常数在,而且这道题对于LCT标记十分难维护,又得乘上4,5然后就炸了) ...

  7. 并查集 + 线段树 LA 4730 Kingdom

    题目传送门 题意:训练指南P248 分析:第一个操作可以用并查集实现,保存某集合的最小高度和最大高度以及城市个数.运用线段树成端更新来统计一个区间高度的个数,此时高度需要离散化.这题两种数据结构一起使 ...

  8. YYHS-猜数字(并查集/线段树维护)

    题目描述     LYK在玩猜数字游戏.    总共有n个互不相同的正整数,LYK每次猜一段区间的最小值.形如[li,ri]这段区间的数字的最小值一定等于xi.     我们总能构造出一种方案使得LY ...

  9. luogu5012 水の数列 (并查集+线段树)

    如果我们能求出来每个区间个数的最大分值,那就可以用线段树维护这个东西 然后出答案了 然后这个的求法和(luogu4269)Snow Boots G非常类似,就是我们把数大小排个序,每次都拿<=x ...

随机推荐

  1. cocos2d JS 艺术字特殊符号的显示

    this.setSocreAtion(score, this.tfMoneyList[index],mun); //传入分数与对象,调用下面的函数 setSocreAtion : function ( ...

  2. 题外话:Lua脚本语言存在的意义

    纯属个人见解. 大致来说:c/c++执行效率高,游戏中一些性能敏感的复杂计算需要用c/c++来实现,防止游戏卡顿和低帧率.这些复杂计算包括战斗逻辑,复杂AI,骨骼动画蒙皮骨骼点的坐标计算等等.但c++ ...

  3. HDU 4565 So Easy(矩阵解公式)

    So Easy [题目链接]So Easy [题目类型]矩阵解公式 &题解: 感觉这种类型的题都是一个套路,这题和hdu 2256就几乎是一样的. 所以最后2Xn就是答案 [时间复杂度]\(O ...

  4. 集体干死java 在启动.sh

    #!/bin/bash#reboot .jar#author wangdonghuipid=`ps -ef |grep java |awk '{print $2}'`echo $pidecho'--- ...

  5. Mysql导出(多张表)表结构及表数据 mysqldump用法

        命令行下具体用法如下:  mysqldump -u用戶名 -p密码 -d 數據库名 表名 脚本名; 1.导出數據库為dbname的表结构(其中用戶名為root,密码為dbpasswd,生成的脚 ...

  6. TP文件上传

    一.单文件上传 <form action="__ACTION__" enctype="multipart/form-data" method=" ...

  7. Python 模型定义 :通过pymysql和数据模型(models.py)创建mysql表及表结构

    一.model的配置 1.创建数据库 2.安装pymysql 3.修改配置文件 数据库连接配置 DATABASES = { 'default': { 'ENGINE': 'django.db.back ...

  8. hive中安装hive_utils模块

    1. 因为在linux部署的python 3.6 在安装模块的时候遇到了许多问题,所以使用linux中的python3.6环境 2. 首先使用pip安装 hive_utils 模块sudo pip i ...

  9. Unity shader学习之屏幕后期处理效果之均值模糊

    均值模糊,也使用卷积来实现,之不过卷积中每个值均相等,且相加等于1. 代码如下, 子类: using UnityEngine; public class MeanBlurRenderer : Post ...

  10. Spark学习之路 (六)Spark Transformation和Action

    Transformation算子 基本的初始化 java static SparkConf conf = null; static JavaSparkContext sc = null; static ...