POJ - 3694 - Network

给定一张N个点M条边的无向连通图,然后执行Q次操作,每次向图中添加一条边,并且询问当前无向图中“桥”的数量。N≤105,M≤2∗105,Q≤1000N≤10^5,M≤2*10^5,Q≤1000N≤105,M≤2∗105,Q≤1000。

首先运行一次tarjan,求出桥和缩点,那么无向图缩点为一棵树,树边正好是原来的桥。每次操作连接两点,看看这两点是不是在同一个缩点内,如果是,那么缩点后的树没任何变化,如果两点属于不同的缩点,那么连接起来,然后找这两个缩点的LCA,,因为从点u到LCA再到点v再到点u,将形成环,里面的树边都会变成不是桥。计数的时候注意,有些树边可能之前已经被标记了,这次再经过不能再标记
利用并查集优化,当树上的边不再是桥了以后,就把这条边的子结点所在的集合合并到父节点所在的集合上,这样从c[x]c[x]c[x]走到LCA(c[x],c[y])LCA(c[x],c[y])LCA(c[x],c[y])时,每一步可以直接走到并查集Get返回的结点上,利用并查集对不再是桥的边进行路径压缩,这样将时间复杂度从原来的O(M+Q∗N)O(M+Q*N)O(M+Q∗N)优化到O(M+QlogN)O(M+QlogN)O(M+QlogN)
(第一次走的时候没有任何影响,但是再往后的数据,再次走到了以后会直接把前面走过的不用走的路全部跳过去,达到优化的目的)
 
AC代码:

//这道题代码虽然比较长,但是每个函数各司其职,井井有条,写起来非常舒服
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<math.h>
#include<cstring>
#include<bitset>
#include<vector>
#include<queue>
#define ls (p<<1)
#define rs (p<<1|1)
#define over(i,s,t) for(register int i = s;i <= t;++i)
#define lver(i,t,s) for(register int i = t;i >= s;--i)
//#define int __int128
#define lowbit(p) p&(-p)
using namespace std;typedef long long ll;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5+7;
const int M = 5e5+7;int head[N],nex[M],ver[M],tot = 1;//原图
int hc[N],nc[M],vc[M],tc = 1;//缩点后建图
int dfn[N],low[N],num;//tarjan专用
int dcc,cnt;//强连通专用
int n,m,t,T;//输入专用
bool bridge[M];//割边专用
int deep[N],f[N][20];//LCA专用
int c[N];//缩点专用
int fa[N];//并查集专用void add(int x,int y){ver[++tot] = y;nex[tot] = head[x];head[x] = tot;
}void add_c(int x,int y){vc[++tc] = y;nc[tc] = hc[x];hc[x] = tc;
}void tarjan(int x,int in_edge){dfn[x] = low[x] = ++num;for(int i = head[x];i;i = nex[i]){int y = ver[i];if(!dfn[y]){tarjan(y,i);low[x] = min(low[x],low[y]);if(low[y] > dfn[x])bridge[i] = bridge[i ^ 1] = true;//成对变换}else if(i != (in_edge ^ 1))//i和in_edge都是前向星的指针编号low[x] = min(low[x],dfn[y]);}
}void dfs(int x){c[x] = dcc;for(int i = head[x];i;i = nex[i]){int y = ver[i];if(c[y] || bridge[i])continue;dfs(y);}
}queue<int>q;void bfs(){//求的是缩点后的图deep[1] = 1;//根节点的深度是1q.push(1);while(q.size()){int x = q.front();q.pop();for(int i = hc[x];i;i = nc[i]){int y = vc[i];if(deep[y])continue;deep[y] = deep[x] + 1;f[y][0] = x;over(j,1,19)f[y][j] = f[f[y][j - 1]][j - 1];q.push(y);}}
}int lca(int x,int y){if(deep[x] > deep[y])swap(x,y);lver(i,18,0)if(deep[f[y][i]] >= deep[x])y = f[y][i];if(x == y)return x;lver(i,18,0)if(f[x][i] != f[y][i])x = f[x][i],y = f[y][i];return f[x][0];
}int Get(int x){if(x == fa[x])return x;return fa[x] = Get(fa[x]);
}int main()
{while(scanf("%d%d",&n,&m) != EOF && n){tot = 1;dcc = num = 0;over(i,1,n)head[i]  = hc[i] = dfn[i] = low[i] = deep[i] = c[i] = 0;over(i,1,2 * m + 1)bridge[i] = 0;over(i,1,m){int x,y;scanf("%d%d",&x,&y);add(x,y);add(y,x);}over(i,1,n)if(!dfn[i])tarjan(i,0);//两个套路都一样over(i,1,n)if(!c[i])++dcc,dfs(i);//缩完点该建图了tc = 1;over(i,2,tot){//建图就用到了成对变换int x = ver[i ^ 1],y = ver[i];if(c[x] == c[y])continue;add_c(c[x],c[y]);//因为之前是无向图转有向图是双边,这里已经是有向图了只需要建单边即可}//lca预处理bfs();//并查集初始化over(i,1,dcc)fa[i] = i;scanf("%d",&t);int ans = dcc - 1;//dcc是缩点后的点数,而ans是边数,所以最开始ans,树的边数等于点数 - 1printf("Case %d:\n", ++T);while(t--){int x,y;scanf("%d%d",&x,&y);x = c[x],y = c[y];int p = lca(x,y);x = Get(x);while(deep[x] > deep[p]){fa[x] = f[x][0];//先给fa赋值ans--;x = Get(x);//这样get的时候x也能往上走}y = Get(y);while(deep[y] > deep[p]){fa[y] = f[y][0];ans--;y = Get(y);}printf("%d\n",ans);}cout<<endl;}return 0;
}

【割边缩点】解题报告:POJ - 3694 - Network(Tarjan割边缩点 + LCA + 并查集优化)相关推荐

  1. POJ - 3694 Network(边双缩点+LCA+并查集优化)

    题目链接:点击查看 题目大意:给出一个由n个点组成的无向图,现在有m次操作,每次操作都会向图中增加一条无向边,每次操作后询问当前图中有多少个桥 题目分析:题意很好理解,思路也很好想,就是代码量有点小多 ...

  2. POJ - 3694 Network tanjar割边+lca

    题目链接 思路:跑一边tanjar将所有的割边u->v标记为cut[v]=true,表示u->v这条边为割边.然后记录总的割边数ans,每次从两个询问点暴力往上边在跑直到LCA,如果碰到c ...

  3. POJ 3694 (tarjan缩点+LCA+并查集)

    好久没写过这么长的代码了,题解东哥讲了那么多,并查集优化还是很厉害的,赶快做做前几天碰到的相似的题. 1 #include <iostream> 2 #include <algori ...

  4. POJ 1703 Find them, Catch them(路径压缩并查集)

    POJ 1703 Find them, Catch them(路径压缩并查集) 2014年03月11日 20:13:54 阅读数:881 POJ 1703 Find them, Catch them( ...

  5. POJ 3694 Network ★(边双连通分量+并查集缩点+LCA)

    [题意]一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(每次回答是在上一次连边的基础之上) [分析]好题,做完后涨了很多姿势~ 普通做法当然就是每加 ...

  6. POJ 3694 Network(tarjan+lca+并查集)

    题目 给定一张NNN个点MMM条边的无向连通图,然后执行QQQ次操作,每次向图中添加一条边,并且询问当前无向图中"桥"的数量. 题解 先求出图中所有的边双,然后缩点 令c[x],c ...

  7. POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)

    [题意]: 有N个结点M条边的图,有Q次操作,每次操作在点x, y之间加一条边,加完E(x, y)后还有几个桥(割边),每次操作会累积,影响下一次操作. [思路]: 先用Tarjan求出一开始总的桥的 ...

  8. POJ 1984 Navigation Nightmare 【经典带权并查集】

    任意门:http://poj.org/problem?id=1984 Navigation Nightmare Time Limit: 2000MS   Memory Limit: 30000K To ...

  9. poj解题报告——poj 1528 Perfection

    原题入口 poj 1528 Perfection 题目描述 Perfection Time Limit: 1000MS Memory Limit: 10000K Total Submissions: ...

最新文章

  1. MinIO分布式专题(第一章、一文教你搭建MinIO单机版)
  2. jQuery 常用的效果函数(一)
  3. 一堂如何提高代码质量的培训课【转】
  4. jca oracle官方文档,Oracle 官方文档说明
  5. python编程少儿游戏编程_少儿编程课堂|python – 用游戏学编程
  6. linux guard什么进程,使用linux系统性能监控工具KSysguard监控远端主机介绍
  7. 不停机上线服务_手机停机也能迅速交话费!微信和三大运营商联手开了“绿色通道”...
  8. LeetCode每日一题:14.longest-common-prefix(最长公共前缀)
  9. mysql关闭显示无权限_如何关闭mysql远程登录权限
  10. Android中文URL乱码问题 解决
  11. sql添加字段和字段说明
  12. python 爬取视频ts文件_python爬取视频网站中video标签的m3u8文件与ts文件
  13. 计算机语言echo off什么意思,批处理文件的@echo off是什么意思?
  14. checkio Ascending List
  15. 天啦噜,小白后台的一波新功能,看完世界杯 看这里!(最后有福利 哦~~)
  16. TCP/IP传输层协议实现 - TCP的坚持定时器(lwip)
  17. 黄金分割法 ( 三分法 )
  18. Linux下挂载NTFS分区
  19. java的jna电脑桌面背景_获取bing图片并自动设置为电脑桌面背景(使用 URLDownloadToFile API函数)...
  20. 白领沉迷EXCEL式生存

热门文章

  1. 计算机视觉系统中图像究竟经历了哪些“折磨”
  2. OpenCV使用CUDA处理图像的教程与实战
  3. 编程——无序数组中找到最大乘积(python)
  4. Plan9操作系统基本概念
  5. PAT - L1-020. 帅到没朋友(裸并查集)
  6. 移动分发端 基础统计指标经典业务代码节选--留存用户统计
  7. 基于用户画像 《列变行》 特征打标显示
  8. Apache Spark源码走读之8 -- Spark on Yarn
  9. 如果在BackgroundWorker运行过程中关闭窗体…
  10. 在Eclipse中的Android项目里实现代码复用