1. 程式人生 > >Codeforces 1140F Extending Set of Points 線段樹 + 按秩合並並查集 (看題解)

Codeforces 1140F Extending Set of Points 線段樹 + 按秩合並並查集 (看題解)

!= space https air c++ merge puts problem ase

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 線段樹 + 按秩合並並查集 (看題解)