正解是线段树。。。
可惜我不会这么高级的操作。。。
(实际上是我抄学长的代码,结果TLE了)
然后过了一个月,在CF上学到了rollback 这种灵活处理动态图的方法,于是就秒了。
简单来说 rollback 就是暴力记录每个变量过去的值,就可以随时退回到原来的某个状态了。
当然必须要求每次对变量的修改要少,至于少多少得看题目,并查集几乎是常数,所以最后的复杂度接近线性。非常劲。
下面是具体操作。
void change(int &old, int nw) {
addr.push(&old);
val.push(old);
st++;
old = nw;
}
void rollback(int old) {
while (st > old) {
st--;
*addr.top() = val.top();
addr.pop();
val.pop();
}
}
修改的话,用线段树维护每个时间点的状态就好了。然后在线段树上做DFS就可以了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int st;
stack<int*> addr;
stack<int> val;
void change(int &old, int nw) {
addr.push(&old);
val.push(old);
st++;
old = nw;
}
void rollback(int old) {
while (st > old) {
st--;
*addr.top() = val.top();
addr.pop();
val.pop();
}
}
int C;
char info[N][10];
int r1[N], r2[N], c1[N], c2[N];
map<pair<int, int>, int> showtime;
bool ans[N];
vector< pair<int, int> > event[N << 2], quest[N << 2];
void add_event(int o, int l, int r, int el, int er, int p1, int p2) {
if (el <= l && r <= er) {
event[o].push_back(make_pair(p1, p2));
} else {
int mid = (l + r) >> 1;
if (mid >= el) {
add_event(o << 1, l, mid, el, er, p1, p2);
}
if (mid + 1 <= er) {
add_event(o << 1 | 1, mid+1, r, el, er, p1, p2);
}
}
}
void add_query(int o, int l, int r, int tim, int p1, int p2) {
if (l == r) {
quest[o].push_back(make_pair(p1, p2));
} else {
int mid = (l + r) >> 1;
if (tim <= mid) {
add_query(o << 1, l, mid, tim, p1, p2);
} else {
add_query(o << 1 | 1, mid+1, r, tim, p1, p2);
}
}
}
int ask;
int fa[N << 1], rnk[N << 1];
int find(int x) {
return x == fa[x] ? x : find(fa[x]);
}
bool same(int x, int y) {
return find(x) == find(y);
}
void unite(int x, int y) {
x = find(x), y = find(y);
if (x != y) {
if (rnk[x] < rnk[y]) {
change(fa[x], y);
change(rnk[y], rnk[y] + rnk[x]);
} else {
change(fa[y], x);
change(rnk[x], rnk[x] + rnk[y]);
}
}
}
void solve(int o, int l, int r) {
int cur = st;
for (int i = 0; i < event[o].size(); i++) {
pair<int, int> &e = event[o][i];
unite(e.first, e.second);
}
if (l == r) {
for (int i = 0; i < quest[o].size(); i++) {
pair<int, int> &e = quest[o][i];
ans[++ask] = same(e.first, e.second);
}
} else {
int mid = (l + r) >> 1;
solve(o << 1, l, mid);
solve(o << 1 | 1, mid+1, r);
}
rollback(cur);
}
int main() {
scanf("%d", &C);
int tim = 0;
while (++tim) {
scanf("%s", info[tim]);
if (info[tim][0] == 'E') {
break;
} else {
scanf("%d %d %d %d", &r1[tim], &c1[tim], &r2[tim], &c2[tim]);
}
}
int scale = tim;
tim = 0;
while (++tim < scale) {
int p1 = (r1[tim] - 1) * C + c1[tim], p2 = (r2[tim]- 1) * C + c2[tim];
if (p1 > p2) swap(p1, p2);
if (info[tim][0] == 'O') {
showtime[make_pair(p1, p2)] = tim;
} else
if (info[tim][0] == 'C') {
add_event(1, 1, scale, showtime[make_pair(p1, p2)], tim, p1, p2);
showtime.erase(make_pair(p1, p2));
} else {
add_query(1, 1, scale, tim, p1, p2);
}
}
for (map<pair<int, int>, int>::iterator it = showtime.begin(); it != showtime.end(); ++it) {
add_event(1, 1, scale, it->second, scale, it->first.first, it->first.second);
}
ask = 0;
for (int i = 1; i <= 2 * C; i++) {
fa[i] = i;
rnk[i] = 1;
}
solve(1, 1, scale);
for (int i = 1; i <= ask; i++) {
puts(ans[i] ? "Y" : "N");
}
return 0;
}