感谢Inspector_Javert的这篇博客,让我看懂了什么是线段树分治。
首先我们要知道如何判定一个图是不是二分图,那就是这个图不存在奇环。然后我们可以以时间为轴建立线段树,把每条边放到线段树中,由线段树的性质我们可以知道每条边最多出现 log n \log n logn次,然后我们深搜这棵时间线段树,每次把路径上的所有节点上的所有边全部加入,然后判定当前图是不是二分图,那么现在问题就被我们转化成了给定一些边(支持删除)的二分图判定问题,我们考虑来解决这个问题。
我们可以用一个按秩合并的带权并查集来实现,每个点记录到父亲的树上距离,每次在连通图上加边时判定路径长度奇偶性即可,每次加入一条边 ( x , y ) (x,y) (x,y)时,设 x x x在并查集的根节点为 u u u, y y y在并查集的根节点为 v v v,那么 u u u到 v v v的距离就是 u − x − y − v u-x-y-v u−x−y−v的距离,这个东西暴力查找就好了,支持删除也很简单,因为这里的边都是按顺序加入的,删除的时候也只会删除最后加入的几条边,我们用一个栈把每次修改的信息存下来,删除的时候把栈中的信息还原即可,复杂度 O ( n log 2 n ) O(\text{n log}^2\text{n}) O(n log2n)。
#include
#define x first
#define y second
#define pb push_back
#define mp make_pair
#define inf (0x3f3f3f3f)
#define mem(a, b) memset(a, b, sizeof(a))
#define Rep(i, a) for (int i = 0; i < a; ++ i)
#define For(i, a, b) for (int i = a; i <= b; ++ i)
#define Forr(i, a, b) for (int i = a; i >= b; -- i)
#define Travel(i, x) for (int i = head[x]; i; i = nxt[i])
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
template<class T>inline T read(T &_) {
T __ = getchar(), ___ = 1; _ = 0;
for (; !isdigit(__); __ = getchar()) if (__ == '-') ___ = -1;
for (; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
return _ *= ___;
}
template<class T>inline bool chkmax(T &_, T __) { return _ < __ ? _ = __, 1 : 0; }
template<class T>inline bool chkmin(T &_, T __) { return _ > __ ? _ = __, 1 : 0; }
inline void proStatus() {
ifstream t("/proc/self/status");
cout << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>());
}
const int N = 1e5 + 7;
int n, m, q, ans[N];
struct Union_Find_Set {
struct node {
int x, y, d;
} S[N];
int fa[N], dep[N], dis[N], top;
Union_Find_Set() { Rep(i, N) fa[i] = i; }
int find(int x) { return x == fa[x] ? x : find(fa[x]); }
int getdis(int x) { return x == fa[x] ? dis[x] : dis[x] + getdis(fa[x]); }
bool merge(int x, int y, int &cnt) {
int ax = find(x), ay = find(y);
if (ax ^ ay) {
S[++ top] = (node) { ax, ay, dis[ax] }, ++ cnt;
dis[ax] = getdis(x) + getdis(y) + 1, fa[ax] = ay;
if (dep[ax] == dep[ay]) ++ dep[ay];
} else {
int disx = getdis(x), disy = getdis(y);
if ((disx + disy + 1) & 1) return false;
}
return true;
}
void recall() {
node now = S[top --];
if (dep[now.x] == dep[now.y] - 1)
-- dep[now.y];
fa[now.x] = now.x, dis[now.x] = now.d;
}
} Set;
struct Segment_Tree {
#define ls (bh << 1)
#define rs (ls | 1)
#define mid ((l + r) >> 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r
vector<PII> S[N << 2];
void update(int bh, int l, int r, int x, int y, PII z) {
if (x <= l && r <= y) S[bh].pb(z);
else {
if (x <= mid) update(lson, x, y, z);
if (y > mid) update(rson, x, y, z);
}
}
void Solve(int bh, int l, int r) {
int sz = S[bh].size(), flag = 1, cnt = 0;
Rep(i, sz) flag &= Set.merge(S[bh][i].x, S[bh][i].y, cnt);
if (l == r) ans[l] = flag;
else if(flag) Solve(lson), Solve(rson);
Rep(i, cnt) Set.recall();
}
} T;
int main() {
//freopen("4025.in", "r", stdin);
//freopen("4025.out", "w", stdout);
int x, y, s, t;
read(n), read(m), read(q);
For(i, 1, m) {
read(x), read(y), read(s), read(t);
T.update(1, 1, q, s + 1, t, mp(x, y));
}
T.Solve(1, 1, q);
For(i, 1, q)
puts(ans[i] ? "Yes" : "No");
return 0;
}