有一类问题,需要支持插入,删除等一些操作。
可能插入比较容易,但是怎么想都不能删除,这时候就需要用到线段树分治了。
具体怎么做?
按操作时间建立一棵线段树。
线段树上每一个节点用 vector
存下一些操作,表示这些操作在这个节点所代表的时间区间生效。
插入完操作后,开始遍历线段树。
进入线段树的一个节点时,加入所有的操作,并在加入操作之前记录下原来的状态(也可以开 vector
记录)。
到根节点时,一个时间点的所有操作都加入完毕,此时可以进行查询操作了。
回溯时要记得还原成未加入操作前的状态。
分析一下复杂度
由于一次操作会在时间线段树上 (log n) 个节点产生贡献,所以复杂度比平常应该是多了一个 (log)。
撤销操作一般复杂度都要小于等于插入操作,所以能插入一般都能撤回。
代码
感觉这道例题可能难点在于带权并查集上,这里挂几篇写的比较好的博客吧。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
int n, m, k;
struct edge { int x, y; } ;
int ou[M], od[M], odist[M], top;
namespace UFS {
int fa[N], d[N], dist[N];
int find(int u) { return fa[u] == u ? u : find(fa[u]); }
int getDist(int u) { return fa[u] == u ? 0 : dist[u] ^ getDist(fa[u]); }
bool merge(int u, int v) {
int x = find(u), y = find(v);
if(x == y) return false;
if(d[x] > d[y]) swap(u, v), swap(x, y);
++top;
ou[top] = x, od[top] = d[y], odist[top] = dist[x];
dist[x] = getDist(u) ^ getDist(v) ^ 1, fa[x] = y, d[y] += (d[x] == d[y]);
return true;
}
void undo() {
int u = ou[top];
d[fa[u]] = od[top];
dist[u] = odist[top];
fa[u] = u;
--top;
}
}
int ll, rr;
edge ce;
namespace SMT {
#define lch(x) (x << 1)
#define rch(x) (x << 1 | 1)
vector<edge> e[N << 2];
void modify(int u, int l, int r) {
if(ll <= l && r <= rr) {
e[u].push_back(ce);
return void();
}
int mid = (l + r) >> 1;
if(ll <= mid) modify(lch(u), l, mid);
if(mid < rr) modify(rch(u), mid + 1, r);
}
void dfs(int u, int l, int r) {
int ecnt = 0;
bool flag = false;
for(size_t i = 0; i < e[u].size(); ++i) {
int x = e[u][i].x, y = e[u][i].y;
if(!UFS::merge(x, y)) {
flag |= (UFS::getDist(x) == UFS::getDist(y));
if(flag) break;
} else {
++ecnt;
}
}
if(flag) for(int i = l; i <= r; ++i) puts("No");
else if(l == r) puts("Yes");
else {
int mid = (l + r) >> 1;
dfs(lch(u), l, mid);
dfs(rch(u), mid + 1, r);
}
for(int i = 1; i <= ecnt; ++i)
UFS::undo();
}
}
int main() {
scanf("%d %d %d", &n, &m, &k);
for(int i = 1; i <= n; ++i)
UFS::fa[i] = i;
for(int i = 1, x, y, l, r; i <= m; ++i) {
scanf("%d %d %d %d", &x, &y, &l, &r);
ce = (edge){x, y};
ll = l + 1, rr = r;
if(ll <= rr) SMT::modify(1, 1, k);
}
SMT::dfs(1, 1, k);
return 0;
}