811 words
4 minutes
Code Forces - 100551A
Solution
This is a template program for divide and conquer on a segment tree. The entire idea is that you build the time line into a segment tree and each edge exist for a certain time period on the tree. There are several details in implementation, please refer to the code.
Full Implementation
// Eating, bathing, having a girlfriend, having an active social life is incidental, it gets in the way of code time.
// Writing code is the primary force that drives our lives so anything that interrupts that is wasteful.
#include <bits/stdc++.h>
using namespace std;
/************************************/
inline int64_t read() { int64_t x = 0, f = 1; char ch = getchar(); while (ch<'0'|| ch>'9') { if(ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar();} return x * f; }
inline int read(char *s) { char ch = getchar(); int i = 1; while (ch == ' ' || ch == '\n') ch = getchar(); while (ch != ' ' && ch != '\n') s[i++] = ch, ch = getchar(); s[i] = '\0'; return i - 1; }
#define fileio(x) freopen((string(x) + ".in").c_str(), "r", stdin), freopen((string(x) + ".out").c_str(), "w", stdout)
typedef int64_t ll; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef long double ld;
ll mod = 1e9 + 7;
#define fi first
#define se second
ll fpow(ll a, ll b, ll md, ll cur = 1) { while (b) { { if (b % 2 == 1) cur *= a; } a *= a, b = b / 2, a %= md, cur %= md; } return cur % md; }
/************************************/
const int N = 3e5 + 5, inf = 0x3f3f3f3f;
int n, m, sum[N << 2];
struct node {
int f, u, v;
node(int _f = 0, int _u = 0, int _v = 0) { f = _f, u = _u, v = _v; }
} qry[N];
struct edg {
int u, v;
bool operator<(const edg &b) const { return u != b.u ? u < b.u : v < b.v; }
};
vector<edg> vec[N << 2];
map<edg, int> mp;
void maintain(int p) { sum[p] = sum[p << 1] + sum[p << 1 | 1]; }
void build(int p = 1, int l = 1, int r = m) {
if (l >= r) {
sum[p] = (qry[l].f == 2);
return;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r), maintain(p);
}
void upd(int L, int R, edg x, int p = 1, int l = 1, int r = m) {
if (l >= L && r <= R) {
vec[p].emplace_back(x);
return;
}
if (l > R || r < L)
return;
int mid = (l + r) >> 1;
upd(L, R, x, p << 1, l, mid), upd(L, R, x, p << 1 | 1, mid + 1, r);
}
int par[N << 1];
int siz[N << 1];
int sol = 0;
vector<pii> hsty;
inline void init() {
for (int i = 1; i <= n; i++) {
par[i] = i;
siz[i] = 1;
}
sol = n;
}
int find(int x) {
if (par[x] == x) return x;
return find(par[x]);
}
void merge(int a, int b) {
a = find(a);
b = find(b);
if (a != b) {
sol--;
if (siz[a] > siz[b]) {
swap(a, b);
}
siz[b] += siz[a];
par[a] = b;
hsty.push_back({a, b});
}
}
int snap() {
return hsty.size();
}
void rlb(int stp) {
while (hsty.size() > stp) {
int a = hsty.back().first;
int b = hsty.back().second;
sol++;
siz[b] -= siz[a];
par[a] = a;
hsty.pop_back();
}
}
void dvc(int p = 1, int l = 1, int r = m) {
if (!sum[p])
return;
int now = snap();
for (edg &x : vec[p])
merge(x.u, x.v);
if (l >= r) {
cout << sol << '\n';
rlb(now);
return;
}
int mid = (l + r) >> 1;
dvc(p << 1, l, mid), dvc(p << 1 | 1, mid + 1, r);
rlb(now);
return;
}
signed main() {
#ifndef LOCAL
fileio("connect");
#endif
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
init();
char op;
int u, v;
for (int i = 1; i <= m; i++) {
cin >> op;
if (op == '?') {
qry[i] = node(2, 0, 0);
} else {
cin >> u >> v;
if (u > v)
swap(u, v);
qry[i] = node(op != '+', u, v);
}
}
for (int i = 1; i <= m; i++) {
edg x = {qry[i].u, qry[i].v};
if (qry[i].f == 0)
mp[x] = i;
if (qry[i].f == 1) {
int l = mp[x], r = i - 1;
upd(l, r, x);
mp.erase(x);
}
}
for (auto &[a, b] : mp)
upd(b, m, a);
build();
dvc();
return 0;
}