卧薪尝胆,厚积薄发。
二分图
Date: Fri Jul 13 13:37:05 CST 2018 In Category: NoCategory

Description:

有一个 $n$ 个节点的图。在 $T$ 时间内一些边会出现后消失。求出每一时间段内这个图是否是二分图。
$n\le100000$ , $m\le200000$ , $T\le100000$

Solution:

对时间分治,用可撤回的按秩合并的带偏移量的并查集维护。每次加一条边时判断是否形成奇环即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<vector>
#include<cstring>
using namespace std;
#define MAXN 100010
int n,m,t;
struct edge
{
int x,y,l,r;
edge(int a = 0,int b = 0,int c = 0,int d = 0){x = a;y = b;l = c;r = d;}
};
int stack[MAXN << 1],top = 0;
namespace Union_Find_Set
{
int f[MAXN],rank[MAXN],g[MAXN];
int find(int x){return (x == f[x] ? x : find(f[x]));}
int dis(int x){return (x == f[x] ? 0 : (g[x] ^ dis(f[x])));}
void merge(int x,int y,int z)
{
x = find(x);y = find(y);
if(x == y)return;
if(rank[x] > rank[y])swap(x,y);
if(rank[x] == rank[y])
{
++rank[y];
stack[++top] = -y;
}
f[x] = y;g[x] = z;stack[++top] = x;
return;
}
void reset(int bottom)
{
while(top > bottom)
{
if(stack[top] < 0)rank[-stack[top]]--;
else{f[stack[top]] = stack[top];g[stack[top]] = 0;}
--top;
}
return;
}
}
#define mid ((l + r) >> 1)
void divide(int l,int r,vector<edge> e)
{
using namespace Union_Find_Set;
vector<edge>::iterator it;
int bottom = top;
vector<edge> le,ri;
for(it = e.begin();it != e.end();++it)
{
if(it -> l == l && it -> r == r)
{
int _x = find(it -> x),_y = find(it -> y);
int _z = dis(it -> x) ^ dis(it -> y) ^ 1;
if(_x != _y)
merge(_x,_y,_z);
else if(_z & 1)
{
for(int i = l;i <= r;++i)
puts("No");
reset(bottom);
return;
}
}
else if(it -> r <= mid)le.push_back(*it);
else if(it -> l >= mid + 1)ri.push_back(*it);
else
{
le.push_back(edge(it -> x,it -> y,it -> l,mid));
ri.push_back(edge(it -> x,it -> y,mid + 1,it -> r));
}
}
if(l == r)puts("Yes");
else
{
divide(l,mid,le);
divide(mid + 1,r,ri);
}
reset(bottom);
return;
}
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 1) + (res << 3) + c - '0';
c = getchar();
}
return res;
}
int main()
{
edge e;
using namespace Union_Find_Set;
vector<edge> v;
scanf("%d%d%d",&n,&m,&t);
for(int i = 1;i <= n;++i)
{
f[i] = i;
}
for(int i = 1;i <= m;++i)
{
e.x = read();e.y = read();e.l = read();e.r = read();
++e.l;
if(e.l > e.r)continue;
v.push_back(e);
}
divide(1,t,v);
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡