JZOJ4769. graph
2016-09-11 12:12
162 查看
题目大意
给定n个点和m个操作,每个操作是增加一条边(u,v)或者删除之前的一条边。询问每次操作后的图是否是二分图。
Data Constraint
n,m≤300000
题解
这题是一个比较经典的动态二分图问题。做法挺多,这里讲一种分治的做法(还可以LCT?)。首先,得到了加边与删边操作就等于我们知道了一条边存在的时间段。
考虑按时间分治。假设当前我们分治的时间段是[L,R],设在这个时段出现过的边集合为E。如果存在(u,v)∈E存在的时间恰好为[L,R]我们就把这条边加入并查集(用并查集维护两点间的距离的奇偶性),如果此时出现了奇环,那就表明[L,R]的图都不是二分图。然后就把边分成两组递归下去求解。
时间复杂度:O(mlog2m)
SRC
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std ; #define N 300000 + 10 #define VEDGE vector < Edge > struct Edge { int u , v ; int st , ed ; } ; VEDGE E ; int S ; int fa , Len , Rank ; int Ans ; int n , m , top , Cnt ; int Get( int x ) { return fa[x] == x ? x : Get(fa[x]) ; } inline int Find( int x ) { int ret = 0 ; while ( fa[x] != x ) { ret ^= Len[x] ; x = fa[x] ; } return ret ; } inline void ReSet( int Goal ) { while ( top > Goal ) { if ( S[top] < 0 ) { S[top] = -S[top] ; Rank[S[top]] -- ; } else { Len[S[top]] = 0 ; fa[S[top]] = S[top] ; } S[top] = 0 ; top -- ; } } void DIV( int l , int r , VEDGE G ) { if ( l > r ) return ; VEDGE LE , RE ; LE.clear() , RE.clear() ; int mid = (l + r) / 2 , Origin = top , Num = G.size() ; for (int i = 0 ; i < Num ; i ++ ) { Edge e = G[i] ; if ( e.st == l && e.ed == r ) { int fx = Get(e.u) ; int fy = Get(e.v) ; if ( fx == fy ) { if ( (Find(e.u) ^ Find(e.v) ^ 1) ) { ReSet( Origin ) ; return ; } continue ; } if ( Rank[fx] > Rank[fy] ) swap( fx , fy ) ; Len[fx] = (Find(e.u) ^ Find(e.v) ^ 1) ; fa[fx] = fy ; S[++top] = fx ; if ( Rank[fx] == Rank[fy] ) Rank[fy] ++ , S[++top] = -fy ; continue ; } if ( e.ed <= mid ) LE.push_back(e) ; else if ( e.st > mid ) RE.push_back(e) ; else { int oed = e.ed ; e.ed = mid ; LE.push_back(e) ; e.ed = oed ; e.st = mid + 1 ; RE.push_back(e) ; } } if ( l == r ) { Ans[l] = 1 ; return ; } DIV( l , mid , LE ) ; DIV( mid + 1 , r , RE ) ; ReSet( Origin ) ; } int main() { freopen( "graph.in" , "r" , stdin ) ; freopen( "graph.out" , "w" , stdout ) ; scanf( "%d%d" , &n , &m ) ; for (int i = 1 ; i <= n ; i ++ ) fa[i] = i ; for (int i = 1 ; i <= m ; i ++ ) { int op ; scanf( "%d" , &op ) ; if ( op ) { int a , b ; scanf( "%d%d" , &a , &b ) ; Edge e ; e.u = a + 1 ; e.v = b + 1 ; e.st = i ; e.ed = m ; E.push_back(e) ; } else { int a ; scanf( "%d" , &a ) ; E[a].ed = i - 1 ; } } DIV( 1 , m , E ) ; for (int i = 1 ; i <= m ; i ++ ) { if ( Ans[i] ) printf( "YES\n" ) ; else printf( "NO\n" ) ; } return 0 ; }
以上.
相关文章推荐
- iOS中(相册)摄像头获取的图片上传至服务器被自动旋转了
- win10启动慢
- jQuery的扩展方法写法
- Cesium学习笔记(2)
- I2C接口与SPI和UART接口的区别
- 初识《大话设计模式》
- java多线程:synchronized
- 京东校招2017届应届生java研发岗,面试一,感想
- CCF 201509-3 我参考别人 100分
- Python 错误和异常小结
- mtk Android 常用编译命令
- Codeforces Problem 712C Memory and De-Evolution(贪心,逆推)
- HDU1548-A strange lift
- PHP入门教程之会话控制技巧(cookie与session)
- [置顶] HDU 4592 Boring Game(高斯消元好题)
- 为JavaScript内置对象扩展方法
- 9. 练习:将Eclipse plug-in转化成Eclipse 4 Application project
- 这个博主简易java部分写的不错,http://www.diguage.com/archives
- SQL 101 关键字 语句 注释
- django(5):数据库模型models