题意

给一个连通的无向图,有两种询问:

  • \(a, b, c, d\),问如果删掉\(c,d\)之间的边,\(a,b\)之间是否还连通
  • \(a, b, c\),问如果删掉顶点\(c\),\(a,b\)之间是否还连通

分析

首先DFS一遍求出进入节点的时间戳\(pre(u)\),离开节点的时间戳\(post(u)\)以及当前节点的子树中能连接到的最小的DFS序\(low(u)\)。

然后预处理一下\(u\)的\(2^i\)级祖先,方便计算\(u\)的任意级祖先。

考虑第一种查询

不妨设\(c\)是\(d\)的儿子节点,如果\(c,d\)之间是一个桥并且\(a,b\)两个节点一个在\(c\)的子树中一个不在,这种情况下是不连通的。

其他情况都是连通的。

考虑第二种查询

分成三种情况讨论:

  • \(a,b\)都在子树\(c\)中,如果\(a,b\)在\(c\)的同一个儿子子树中那么去掉\(c\)是连通的。

    否则,让\(a,b\)往上跳,变成\(c\)的两个儿子。如果\(low(a) \geq pre(c)\)或\(low(b) \geq pre(c)\)有一个成立,那么是不连通的。

  • \(a,b\)只有一个在子树\(c\)中,由于对称性,不妨假设\(a\)在子树\(c\)中。

    同样让\(a\)往上跳,变成\(c\)的儿子。如果\(low(a) \geq pre(c)\)那么不连通,否则连通。

  • \(a,b\)都不在子树\(c\)中,那么去掉\(c\)完全没有任何影响,所以还是连通的。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = 100000 + 10;
const int maxm = 1000000 + 10; struct Edge
{
int v, nxt;
Edge() {}
Edge(int v, int nxt): v(v), nxt(nxt) {}
}; int ecnt, head[maxn];
Edge edges[maxm]; void AddEdge(int u, int v) {
edges[ecnt] = Edge(v, head[u]); head[u] = ecnt++;
edges[ecnt] = Edge(u, head[v]); head[v] = ecnt++;
} int n, m; int fa[maxn], dep[maxn];
int dfs_clock, pre[maxn], post[maxn], low[maxn];
bool isbridge[maxn], iscut[maxn]; void dfs(int u) {
bool flag = false;
int child = 0;
pre[u] = low[u] = ++dfs_clock;
for(int i = head[u]; ~i; i = edges[i].nxt) {
int v = edges[i].v;
if(v == fa[u] && !flag) { flag = true; continue; }
child++;
if(!pre[v]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs(v);
low[u] = min(low[u], low[v]);
if(low[v] >= pre[u]) {
iscut[u] = true;
if(low[v] > pre[u]) isbridge[v] = true;
}
} else low[u] = min(low[u], pre[v]);
}
if(u == 1 && child == 1) iscut[u] = false;
post[u] = dfs_clock;
} int anc[maxn][20]; void preprocess() {
memset(anc, 0, sizeof(anc));
for(int i = 1; i <= n; i++) anc[i][0] = fa[i];
for(int j = 1; (1 << j) < n; j++)
for(int i = 1; i <= n; i++) if(anc[i][j-1])
anc[i][j] = anc[anc[i][j-1]][j-1];
} int upward(int u, int x) {
for(int i = 0; i < 20; i++)
if((x >> i) & 1) u = anc[u][i];
return u;
} int insubtree(int u, int v) {
if(pre[v] <= pre[u] && pre[u] <= post[v]) return 1;
return 0;
} bool juedgeVertex(int a, int b, int c) {
int in1 = insubtree(a, c);
int in2 = insubtree(b, c);
if(in1 & in2) {
a = upward(a, dep[a] - dep[c] - 1);
b = upward(b, dep[b] - dep[c] - 1);
if(a == b) return true;
if(low[a] >= pre[c]) return false;
if(low[b] >= pre[c]) return false;
}
if(in1 ^ in2) {
if(!in1) swap(a, b);
a = upward(a, dep[a] - dep[c] - 1);
if(low[a] >= pre[c]) return false;
}
return true;
} int main()
{
while(scanf("%d%d", &n, &m) == 2) {
ecnt = 0;
memset(head, -1, sizeof(head));
while(m--) {
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v);
} dfs_clock = 0;
memset(pre, 0, sizeof(pre));
memset(isbridge, false, sizeof(isbridge));
memset(iscut, false, sizeof(iscut));
dfs(1);
preprocess(); int q;
scanf("%d", &q);
while(q--) {
int op, a, b, c, d;
scanf("%d%d%d%d", &op, &a, &b, &c);
bool ok = true;
if(op == 1) {
scanf("%d", &d);
if(dep[c] < dep[d]) swap(c, d);
int in1 = insubtree(a, c);
int in2 = insubtree(b, c);
if(isbridge[c] && (in1 ^ in2) == 1) ok = false;
} else {
ok = juedgeVertex(a, b, c);
}
printf("%s\n", ok ? "yes" : "no");
}
} return 0;
}

HDU 3896 Greatest TC 双连通分量的更多相关文章

  1. HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 Problem Description Given an undirected connecte ...

  2. HDU 4005 The war 双连通分量 缩点

    题意: 有一个边带权的无向图,敌人可以任意在图中加一条边,然后你可以选择删除任意一条边使得图不连通,费用为被删除的边的权值. 求敌人在最优的情况下,使图不连通的最小费用. 分析: 首先求出边双连通分量 ...

  3. HDU 2460 Network 边双连通分量 缩点

    题意: 给出一个无向连通图,有\(m\)次操作,每次在\(u, v\)之间加一条边,并输出此时图中桥的个数. 分析: 先找出边双连通分量然后缩点得到一棵树,树上的每条边都输原图中的桥,因此此时桥的个数 ...

  4. HDU3896 Greatest TC(双联通分量+倍增)

    Problem Description TC (Tian Chao) is magical place, as you all know...The railways and the rail-sta ...

  5. HDU 2242 考研路茫茫——空调教室(边双连通分量+树形dp+重边标号)

    http://acm.hdu.edu.cn/showproblem.php?pid=2242 题意: 思路:首先求一下双连通分量,如果只有一个双连通分量,那么无论断哪根管子,图还是连通的. 最后只需要 ...

  6. hdu 2460(tarjan求边双连通分量+LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2460 思路:题目的意思是要求在原图中加边后桥的数量,首先我们可以通过Tarjan求边双连通分量,对于边 ...

  7. HDU 4612——Warm up——————【边双连通分量、树的直径】

    Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Stat ...

  8. HDU 3686 Traffic Real Time Query System(双连通分量缩点+LCA)(2010 Asia Hangzhou Regional Contest)

    Problem Description City C is really a nightmare of all drivers for its traffic jams. To solve the t ...

  9. HDU 4612 Warm up(2013多校2 1002 双连通分量)

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Su ...

随机推荐

  1. 使用vuex管理数据

    src/vuex/store.js 组件里面使用引入store.js,注意路径 import store from 'store.js' 然后在使用的组件内data(){}同级放入store 三大常用 ...

  2. git与github的区别

    一直纠结于这俩个的区别,今天有时间翻看了一些有关git的详解终于把这个问题搞得清楚了,大概就是下面的意思: Git是一款免费.开源的分布式版本控制系统 Github是用Git做版本控制的代码托管平台

  3. 【C++函数重载】求3个数中最大的数(分别考虑整数、双精度数、长整数的情况)。

    #include using namespace std; int main( ) { int max(int a,int b,int c); //函数声明 double max(double a,d ...

  4. 【iOS学习笔记】改变状态栏字体颜色

    Step1. info.plist中设置UIViewControllerBasedStatusBarAppearance为NO Step2. AppDelegate.m中添加 - (BOOL)appl ...

  5. HDU 2955 Robberies抢劫案(01背包,变形)

    题意:要抢劫,但是抢每个银行都有被抓的概率,问在低于规定的被抓概率情况下最多能抢到多少钱. 输入:第一行为T,表示共T个测试例子.每个例子的第一行给出一个浮点数P,是规定被抓的概率上限.第一行还有一个 ...

  6. Codeforces 802I Fake News (hard)

    Codeforces 802I 题意:统计所有不同子串出现次数的平方的和. 想法:建一个SAM,$Ans=\sum (step[i]-step[fa[i]])*right[i]^2$ #include ...

  7. flash + php对称密钥加密的交互

    这几天研究了下php和flash中的对称密钥加密的交互问题,经过研究以后决定,在项目中使用aes加密.问题也就来了,在flash中的加密数据如何与php的amf进行数据交互,最终决定使用base64编 ...

  8. 五、react中父子组件间如何传值

    1.父组件向子组件传递数据:父组件绑定属性值传给子组件,子组件通过this.props()接受. 2.子组件向父组件传递数据:子组件绑定一个方法,方法中通过this.props.父组件方法名(参数)传 ...

  9. dubbo + zookeeper 配置

      Dubbo与Zookeeper.SpringMVC整合和使用 windows环境介绍: myeclipse 10 jdk1.6 tomcat 6.0.35 一.安装Zookeeper 1.通过链接 ...

  10. [C++]#if !defined 的作用

    当你用VC的菜单新增一个类,你会发现自动生成的代码总是类似下面的样子: #if !defined(AFX_XXXX__INCLUDED_) #define  AFX_XXXX__INCLUDED_ 具 ...