HDU 4338 Simple Path 点双连通+lca
【题目大意】
给你一个无向图。问,从点u到点v,若是只走简单路径,有多少个点不能到达?
【思路】
这题肯定是要双连通缩点的,以前老是觉得点双连通不会用来缩点,因为割点可以属于多个连通集合,现在立马打脸了 o(╯□╰)o
最开始用,边-双连通思考,然后发现下面这种图就....
如果我们询问(6,7)和(6,4),显然两次点6所属集团的意义不同;除此之外,比方(1,2,3)这个集团,直接合并也是不合理的,询问(1,3)和(3,7),点3的意义也是不同的
问题的关键,其实关键就是割点。如果对点双连通比较熟悉的话,应该能想到:除了孤点,任何点都会至少属于一个连通集合,而只有割点能属于2个及以上的集合。连通集合一定是通过割点相连的。
所以,我们可以考虑把原图改成通过割点相连的形式。上面那个图就可以改成
显然,每条边的一段都是连通集合,而另一段是割点。
仔细分析割点到割点、非割点到非割点、割点到非割点三种情况,你会发现,点u到点v,能走的点就是修改后的图(这个图不会有环)对应的简单路径上的所有的点。比方(2,5)能经过的点就为 {2}∪{1,2,3}∪{3}∪{3,5}∪{5} == {1,2,3,5} ,(2,6)的为 {2}∪{1,2,3}∪{3}∪{3,5}∪{5}∪{4,5,6} == {1,2,3,4,5,6}。
因为路径上的点是有重复的,我们仍需要思考一下。实际上,点的数目,等于每个点的点的数目减去路径上的边数。
而具体怎么去求无环图上一个简单路径上的点数和以及边数和。这里可以采用多种方法,我这里用的lca维护一下。
P.S. 数据好像不严,询问中有点的编号>=n的情况,我这种情况是直接输出n
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const LL INF = 1LL<<55;
const double INFF = 1e100;
const double eps = 1e-8;
const LL mod = 10000000007LL;
const int NN = 100010;
const int MM = 400010;
/* ****************** */int dfn[NN], low[NN], tsp;
int sta[MM], sta_top;
int id[NN], num[NN*2], id_cnt;
int color[NN];
vector<int>bccno[NN];
struct G
{int u, v, next;
}E[MM], E1[MM];
int p1[NN], T1;
int p[NN*2], T;int long2[NN*2*2];
int deep[NN*2], pos[NN*2], dian[NN*2];
int oula[NN*2*2];
int rmq[NN*2*2][20];void init_long2(int n)
{int i;long2[1]=0;for(i=2;i<=n;i++){long2[i]=long2[i-1]+(i==(i&(-i)));}
}void add(int u,int v,G *E,int *p,int &T)
{E[T].u = u;E[T].v = v;E[T].next = p[u];p[u] = T++;
}void bcc(int u,int fa,int col)
{int i, ii, v;dfn[u] = low[u] = ++tsp;color[u] = col;for(i = p1[u]; i + 1; i = E1[i].next){v = E1[i].v;if(dfn[v]==0){sta[++sta_top] = i;bcc(v, u, col);low[u] = min(low[u], low[v]);if(low[v] >= dfn[u]){num[++id_cnt] = 0;for(;;){ii = sta[sta_top--];if(id[ E1[ii].u ] != id_cnt){bccno[ E1[ii].u ].PB(id_cnt);num[id_cnt] ++;id[ E1[ii].u ] = id_cnt;}if(id[ E1[ii].v ] != id_cnt){bccno[ E1[ii].v ].PB(id_cnt);num[id_cnt] ++;id[ E1[ii].v ] = id_cnt;}if(E1[ii].u == u && E1[ii].v == v)break;}}}else if(dfn[v]<dfn[u] && v != fa){sta[++sta_top] = i;low[u] = min(low[u], dfn[v]);}}
}
//生成欧拉序列,计算每个节点深度,每个点首次出现的位置
//其第一个父亲,没有用-1表示
void dfs(int u,int fa,int cen)
{oula[++tsp]=u;deep[u]=cen;pos[u]=tsp;int i,v;for(i=p[u];i+1;i=E[i].next){v=E[i].v;if(v!=fa){dian[v] = dian[u] + num[v];dfs(v,u,cen+1);oula[++tsp]=u;}}
}
//用于lca的rmq
void init_rmq(int n)
{int i,j,en,len;int t1,t2;for(i=1;i<=n;i++)rmq[i][0]=i;for(j=1;j<=long2[n];j++){en=n+1-(1<<j);len=1<<(j-1);for(i=1;i<=en;i++){t1=oula[ rmq[i][j-1] ];t2=oula[ rmq[i+len][j-1] ];if(deep[t1]<deep[t2])rmq[i][j]=rmq[i][j-1];elsermq[i][j]=rmq[i+len][j-1];}}
}
int ask_lca(int u,int v)
{int st=pos[u];int en=pos[v];if(st>en)swap(st,en);int k=long2[en-st+1];int id1=oula[ rmq[st][k] ];int id2=oula[ rmq[en+1-(1<<k)][k] ];if(deep[id1]<deep[id2])return id1;return id2;
}void solve(int n,int sum_n)
{int m,i,u,v,ans;tsp=0;for(i=1;i<=n;i++)pos[i] = -1;for(i=1;i<=n;i++){if(pos[i]==-1){dian[i] = num[i];dfs(i,-1,0);}}init_rmq(tsp);scanf("%d",&m);while(m--){scanf("%d%d",&u,&v);if(u>=sum_n || v>=sum_n){printf("%d\n",sum_n);// while(1);continue;}u++, v++;if(u==v)printf("%d\n", sum_n-1);else if(color[u]!=color[v])printf("%d\n", sum_n);else{u = id[u];v = id[v];i = ask_lca(u, v);ans = dian[u] + dian[v] - dian[i]*2 + num[i];ans -= (deep[u]+deep[v]-deep[i]*2);ans = sum_n - ans;printf("%d\n",ans);}}puts("");
}int main()
{init_long2(100000*4);int n, m, i, j, u, v, si;int ee = 0;while(scanf("%d%d", &n, &m) != EOF){memset(p1, -1, sizeof(p1));T1 = 0;for(i = 0; i < m; i ++){scanf("%d%d", &u, &v);u ++, v ++;add(u, v, E1, p1, T1);add(v, u, E1, p1, T1);}memset(dfn, 0, sizeof(dfn));memset(id, -1, sizeof(id));tsp = 0;id_cnt = 0;sta_top = 0;for(i = 1; i <= n; i ++){if(dfn[i]==0){bcc(i, -1, i);}}memset(p, -1, sizeof(p));T = 0;for(i = 1; i <= n; i ++){si = bccno[i].size();if(si > 1){u = ++id_cnt;id[i] = u;num[u] = 1;for(j = 0; j < si; j ++){v = bccno[i][j];add(u, v, E, p, T);add(v, u, E, p, T);}}bccno[i].clear();}printf("Case #%d:\n",++ee);solve(id_cnt, n);}return 0;
}
HDU 4338 Simple Path 点双连通+lca相关推荐
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
- 图论之tarjan真乃神人也,强连通分量,割点,桥,双连通他都会
先来%一下Robert Tarjan前辈 %%%%%%%%%%%%%%%%%% 然后是热情感谢下列并不止这些大佬的博客: 图连通性(一):Tarjan算法求解有向图强连通分量 图连通性(二):Tarj ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)...
转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2194090a96bbed2db1351de8.html 基本概念: 1.割点:若删掉某点后,原连通图 ...
- HDU 3394 Railway(点双连通分量)
题目大意 一个公园中有 n 个景点,景点之间通过无向的道路来连接,如果至少两个环公用一条路,路上的游客就会发生冲突:如果一条路不属于任何的环,这条路就没必要修 问,有多少路不必修,有多少路会发生冲突 ...
- POJ 3177 Redundant Paths (边双连通+缩点)
<题目链接> <转载于 >>> > 题目大意: 有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走.现已有m条路,求至少要新 ...
- 模板:割点、桥与双连通
文章目录 割点 代码 桥 点双连通分量 代码 边双连通分量 代码 割点 和强连通分量十分相似 分为树枝边.前向边和后向边 注意! if(x!=r&&low[to]>=dfn[x] ...
- poj 3177 Redundant Paths(tarjan边双连通)
题目链接:http://poj.org/problem?id=3177 题意:求最少加几条边使得没对点都有至少两条路互通. 题解:边双连通顾名思义,可以先求一下连通块显然连通块里的点都是双连通的,然后 ...
- Tarjan算法 —— 强连通双连通缩点 模板
TP 强连通缩点模板 双连通缩点模板 边双连通 点双连通 有向图 我们知道在一张 有向无环 图(也叫 DAG)中,肯定存在拓扑序.拓扑序的特殊顺序性质,能够允许我们在 O(n+m)O(n + m)O( ...
- 【FZU】Problem 2181 快来买肉松饼 点双连通
传送门:[FZU]Problem 2181 快来买肉松饼 题目分析:无向图找奇圈的问题.首先我们做tarjan求出点双连通块,每一个块中用黑白染色法得到最长的奇圈,然后这个奇圈中不参加游戏的小孩就是这 ...
最新文章
- 糊涂的教授【拓扑排序】
- 计算机组成原理题库带答案详解,计算机组成原理试试题库(含答案解析) -.doc
- 【Java面试题】49 垃圾回收的优点和原理。并考虑2种回收机制。
- 你必须掌握的20个python代码,短小精悍,用处无穷
- Android NFC开发-实践篇
- 计算机信息管理专业技能评价,计算机信息管理专业个人技能范文
- The GenerateResource task failed unexpectedly. a generic error occured in GDI+
- PBC密码学库使用指南
- 在线扒站工具, 扒站网站工具(简单、快捷、免费)
- 异速联未获取服务器信息,异速联客户端连接服务器的方法
- OA软件详细功能模块列表
- matlab求任意输入响应曲线,3.6 用Matlab进行动态响应分析
- 2019年厦门大学计算机系夏令营经历
- 蒙泰RIP快捷键大全
- TDSCDMA手机N270 新邮通开包尝鲜!
- CakePHP系列(一)----CakePHP3.4一览
- 二分法查找 (长沙戴维营教育)
- 软件架构师应该知道的 97 件事笔记
- 【自动驾驶传感器——摄像头】
- 大智慧服务器 列表不显示,为什么大智慧level 2均线显示不正常!!
热门文章
- 聚划算安卓客户端1期教训总结
- 计算机控制原理实验报告,计算机组成原理实验报告范文
- 电商违禁词查询工具在线检查
- 天心sunlike erp 生产需求分析 按生产订单号生成单号
- MOSS和LCS的集成
- 会议OA项目之会议排座功能会议送审的实现
- signature=152c7128f5309ebd73e4a1d7e8516c1b,交流传动内燃机逻辑控制单元的开发设计
- 《可以量化的经济学》可以购买了,…
- Coursera机器学习(Andrew Ng)笔记:无监督学习与维度约减
- 成都市等2009年《四川省建设工程清单计价定额》人工费调整的批复〔2019〕5号