This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <iostream>
#include <vector>
#include <stack>
#include <cassert>
using namespace std;
struct disjoint_set
{
int N;
vector<int> parent;
vector<int> parent_edge; //the color of this node is the xor of path up to parent
vector<int> subtree;
vector<int> op_node = vector<int>(1, 0);
vector<int> op_oldparent = vector<int>(1, 0);
vector<int> op_oldxor = vector<int>(1, 0);
vector<int> op_time = vector<int>(1, 0);
vector<bool> bipartite = vector<bool>(1, 1);
vector<bool> subtree_change = vector<bool>(1, 0);
int curr_time = 0;
disjoint_set()
{
;
}
disjoint_set(int N_)
{
N = N_;
parent = vector<int>(1+N);
parent_edge = vector<int>(1+N);
subtree = vector<int>(1+N);
for(int i = 1; i <= N; i++)
{
parent[i] = i;
parent_edge[i] = 0;
subtree[i] = 1;
}
}
void add_entry(int u, int v, int x, bool b, bool s)
{
op_node.push_back(u);
op_oldparent.push_back(v);
op_oldxor.push_back(x);
op_time.push_back(curr_time);
bipartite.push_back(b);
subtree_change.push_back(s);
}
void remove_entry()
{
op_node.pop_back();
op_oldparent.pop_back();
op_oldxor.pop_back();
op_time.pop_back();
bipartite.pop_back();
subtree_change.pop_back();
}
pair<int, int> root(int u) //first = root, second = xor of root and u
{
int v = u;
int edg = 0;
while(parent[v] != v)
{
edg ^= parent_edge[v];
v = parent[v];
}
if(v == u || v == parent[u]) return make_pair(parent[u], edg);
add_entry(u, parent[u], parent_edge[u], bipartite.back(), 0);
parent[u] = v;
parent_edge[u] = edg;
return make_pair(parent[u], parent_edge[u]);
}
void join(int u, int v)
{
curr_time++;
pair<int, int> U = root(u);
pair<int, int> V = root(v);
if(U.first == V.first)
{
op_node.push_back(0);
op_oldparent.push_back(0);
op_oldxor.push_back(0);
op_time.push_back(curr_time);
if(U.second == V.second)
{
bipartite.push_back(0);
}
else
{
bipartite.push_back(bipartite.back());
}
subtree_change.push_back(0);
}
else
{
// cerr << "case 2\n";
if(subtree[U.first] < subtree[V.first]) swap(U, V);
// cerr << U.first << ' ' << V.first << '\n';
add_entry(V.first, parent[V.first], parent_edge[V.first], bipartite.back(), 1);
parent[V.first] = U.first;
parent_edge[V.first] = 1 ^ V.second ^ U.second;
subtree[U.first] += subtree[V.first];
// cerr << U.first << ' ' << V.first << ' ' << parent[V.first] << '\n';
}
}
void rollback()
{
while(op_time.back() == curr_time)
{
int u = op_node.back();
int v = op_oldparent.back();
int x = op_oldxor.back();
bool s = subtree_change.back();
remove_entry();
if(s) subtree[ parent[u] ] -= subtree[u];
parent[u] = v;
parent_edge[u] = x;
}
curr_time--;
}
bool is_bipartite()
{
return bipartite.back();
}
};
const int maxN = 200'000;
const int maxM = 200'000;
int N, M, Q;
vector<int> u(1+maxM), v(1+maxM);
vector<int> minR(1+maxN, 0);
//the minimum value of R so that if the roads i, ... R are blocked the graph is bipartite
disjoint_set DSU;
int L;
int R;
void expand_right()
{
R++;
DSU.rollback();
}
void contract_right()
{
R--;
DSU.join(u[R+1], v[R+1]);
}
void expand_left()
{
L--;
DSU.rollback();
}
void contract_left()
{
L++;
DSU.join(u[L-1], v[L-1]);
}
void solve(int l1, int l2, int r1, int r2) // [L, R] == [l1, r2] at the beginning
{
int lmid = (l1+l2)/2;
int rmid;
if(!DSU.is_bipartite())
{
for(int i = lmid; i <= l2; i++)
{
minR[i] = M+1;
}
if(l1 <= lmid-1)
{
solve(l1, lmid-1, r1, r2); //ADJUST L AND R!!!!! -> not necessary
}
return;
}
while(L < lmid)
contract_left();
if(!DSU.is_bipartite())
{
while(l1 < L)
expand_left();
for(int i = lmid; i <= l2; i++)
{
minR[i] = M+1;
}
if(l1 <= lmid-1)
{
solve(l1, lmid-1, r1, r2); //ADJUST L AND R!!!!! -> not necessary
}
return;
}
// if(F) cerr << "check\n";
rmid = r2;
while(DSU.is_bipartite())
{
rmid = min(rmid, R);
contract_right();
}
minR[lmid] = rmid;
while(R < r2)
expand_right();
while(l1 < L)
expand_left();
if(l1 <= lmid-1)
{
while(rmid < R)
contract_right();
solve(l1, lmid-1, r1, rmid);
while(R < r2)
expand_right();
}
if(lmid+1 <= l2)
{
while(L < lmid+1)
contract_left();
solve(lmid+1, l2, rmid, r2);
while(l1 < L)
expand_left();
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> N >> M >> Q;
for(int j = 1; j <= M; j++) cin >> u[j] >> v[j];
DSU = disjoint_set(N);
disjoint_set temp(N);
for(int j = 1; j <= M; j++) temp.join(u[j], v[j]);
if(temp.is_bipartite())
{
int x;
for(int u = 1; u <= Q; u++)
{
cin >> x >> x;
cout << "NO\n";
}
return 0;
}
L = 1;
R = M;
solve(1, M, 1, M);
for(int q = 1; q <= Q; q++)
{
int l, r;
cin >> l >> r;
if(minR[l] <= r) cout << "NO\n"; //bipartite
else cout << "YES\n"; //not bipartite
}
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |