Codeforces 1140F Extending Set of Points 线段树 + 按秩合并并查集 (看题解)
Posted cjlhy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 1140F Extending Set of Points 线段树 + 按秩合并并查集 (看题解)相关的知识,希望对你有一定的参考价值。
我们能发现, 如果把x轴y轴看成点, 那么答案就是在各个连通块里面的x轴的个数乘以y轴的个数之和。
然后就变成了一个并查集的问题, 但是这个题目里面有撤销的操作, 所以我们要把加入和撤销操作变成
这个点影响(L , R)之间的询问, 然后把它丢到线段树里面分成log段, 然后我们dfs一遍线段树, 用按秩合并
并查集取维护, 回溯的时候将并查集撤销。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ull unsigned long long using namespace std; const int N = 3e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; const double eps = 1e-6; const double PI = acos(-1); int n; LL ans[N]; map<PII, int> Map; int fa[N << 1], cntx[N << 1], cnty[N << 1], sz[N << 1]; LL now = 0; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 vector<PII> vc[N << 2]; void Insert(int L, int R, PII e, int l, int r, int rt) { if(l >= L && r <= R) { vc[rt].push_back(e); return; } int mid = l + r >> 1; if(L <= mid) Insert(L, R, e, lson); if(R > mid) Insert(L, R, e, rson); } int getRoot(int x) { return fa[x] == x ? x : getRoot(fa[x]); } void Merge(int x, int y, stack<PII>& stk) { int fax = getRoot(x); int fay = getRoot(y); if(fax != fay) { if(sz[fax] < sz[fay]) swap(fax, fay); stk.push(mk(fax, fay)); now -= 1ll * cntx[fax] * cnty[fax]; now -= 1ll * cntx[fay] * cnty[fay]; sz[fax] += sz[fay]; cntx[fax] += cntx[fay]; cnty[fax] += cnty[fay]; fa[fay] = fax; now += 1ll * cntx[fax] * cnty[fax]; } } void Delete(stack<PII>& stk) { while(!stk.empty()) { int fax = stk.top().fi; int fay = stk.top().se; stk.pop(); now -= 1ll * cntx[fax] * cnty[fax]; sz[fax] -= sz[fay]; cntx[fax] -= cntx[fay]; cnty[fax] -= cnty[fay]; fa[fay] = fay; now += 1ll * cntx[fax] * cnty[fax]; now += 1ll * cntx[fay] * cnty[fay]; } } void dfs(int l, int r, int rt) { stack<PII> stk; for(auto& t : vc[rt]) Merge(t.fi, t.se, stk); if(l == r) ans[l] = now; else { int mid = l + r >> 1; dfs(l, mid, rt << 1); dfs(mid + 1, r, rt << 1 | 1); } Delete(stk); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { PII e; scanf("%d%d", &e.fi, &e.se); e.se += 300000; if(Map.find(e) == Map.end()) { Map[e] = i; } else { Insert(Map[e], i - 1, e, 1, n, 1); Map.erase(e); } } for(auto& t : Map) Insert(t.se, n, t.fi, 1, n, 1); for(int i = 1; i <= 300000; i++) fa[i] = i, cntx[i] = 1, sz[i] = 1; for(int i = 300001; i <= 600000; i++) fa[i] = i, cnty[i] = 1, sz[i] = 1; dfs(1, n, 1); for(int i = 1; i <= n; i++) printf("%lld ", ans[i]); puts(""); return 0; } /* */
以上是关于Codeforces 1140F Extending Set of Points 线段树 + 按秩合并并查集 (看题解)的主要内容,如果未能解决你的问题,请参考以下文章
cf1140f Extending Set of Points