BZOJ 1018: [SHOI2008]堵塞的交通traffic
可惜我不会这么高级的操作。。。
(实际上是我抄学长的代码,结果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; }