Skip to content

Commit 4d610bf

Browse files
authored
[20250903] BOJ / D4 / 그래프와 연결성 쿼리 / 권혁준
1 parent 4a785fd commit 4d610bf

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
```cpp
2+
#pragma GCC optimize("O3, unroll-loops")
3+
#include <bits/stdc++.h>
4+
using namespace std;
5+
using ll = long long;
6+
7+
int N, M, Q, bucketSize;
8+
vector<pair<int,int>> edges;
9+
vector<tuple<int,int,int>> queries;
10+
int res[100000]{};
11+
12+
// disjoint set
13+
int root[100001]{}, cnt[100001]{};
14+
ll ans = 0;
15+
vector<tuple<int,int,int>> works;
16+
ll g(ll x) { return x*(x-1)/2; }
17+
void u(int a, int b) {
18+
int x = a, y = b;
19+
while(x != root[x]) x = root[x];
20+
while(y != root[y]) y = root[y];
21+
if(x == y) {
22+
works.emplace_back(-1,-1,-1);
23+
return;
24+
}
25+
if(cnt[x] > cnt[y]) swap(x,y);
26+
works.emplace_back(x,y,cnt[x]);
27+
ans -= g(cnt[x]) + g(cnt[y]);
28+
cnt[y] += cnt[x];
29+
ans += g(cnt[y]);
30+
root[x] = y;
31+
}
32+
void rollback() {
33+
auto [x,y,r] = works.back(); works.pop_back();
34+
if(x == -1) return;
35+
ans -= g(cnt[y]);
36+
cnt[y] -= r;
37+
ans += g(cnt[x]) + g(cnt[y]);
38+
root[x] = x;
39+
}
40+
41+
// odc
42+
int lifetime[100000]{};
43+
vector<int> infos[262144];
44+
int need[100000]{};
45+
void update(int s, int e, int l, int r, int n, int i) {
46+
if(l>r || l>e || r<s) return;
47+
if(l<=s && e<=r) {
48+
infos[n].push_back(i);
49+
return;
50+
}
51+
int m = (s+e)>>1;
52+
update(s,m,l,r,n*2,i);
53+
update(m+1,e,l,r,n*2+1,i);
54+
}
55+
void clear(int s, int e, int n) {
56+
for(int i:infos[n]) {
57+
auto [a,b] = edges[i];
58+
u(a,b);
59+
}
60+
if(s == e) {
61+
res[need[s]] = ans;
62+
}
63+
else {
64+
int m = (s+e)>>1;
65+
clear(s,m,n*2);
66+
clear(m+1,e,n*2+1);
67+
}
68+
for(int i=0;i<infos[n].size();i++) rollback();
69+
}
70+
71+
int main() {
72+
cin.tie(0)->sync_with_stdio(0);
73+
cout.tie(0);
74+
75+
cin>>N>>M>>Q;
76+
bucketSize = sqrt(M);
77+
iota(root, root+N+1, 0);
78+
fill(cnt, cnt+N+1, 1);
79+
80+
edges.resize(M);
81+
for(auto &[a,b]:edges) cin>>a>>b;
82+
83+
queries.resize(Q);
84+
int tmp = 0;
85+
for(auto &[a,b,c]:queries) cin>>a>>b, a--, b--, c=tmp++;
86+
87+
sort(queries.begin(), queries.end(), [](auto a, auto b) -> bool{
88+
auto [al, ar, ax] = a;
89+
auto [bl, br, bx] = b;
90+
int anum = al/bucketSize, bnum = bl/bucketSize;
91+
if(anum == bnum) {
92+
if(anum & 1) return br < ar;
93+
return ar < br;
94+
}
95+
return anum < bnum;
96+
});
97+
98+
fill(lifetime, lifetime + M, -1);
99+
int pl = 0, pr = 0, px = 0;
100+
for(int i=0;i<Q;i++) {
101+
auto [l, r, x] = queries[i];
102+
need[i] = x;
103+
if(i == 0) {
104+
pl = l, pr = r, px = x;
105+
for(int j=l;j<=r;j++) lifetime[j] = i;
106+
}
107+
else {
108+
while(pl<l) {
109+
if(pl<=pr && lifetime[pl] != -1) update(0,Q-1,lifetime[pl],i-1,1,pl);
110+
lifetime[pl++] = -1;
111+
}
112+
while(l<pl) if(lifetime[--pl] == -1) lifetime[pl] = i;
113+
while(pr<r) {
114+
if(++pr>=l && lifetime[pr] == -1) lifetime[pr] = i;
115+
}
116+
while(r<pr) {
117+
if(lifetime[pr] != -1) update(0,Q-1,lifetime[pr],i-1,1,pr);
118+
lifetime[pr--] = -1;
119+
}
120+
}
121+
}
122+
for(int i=0;i<M;i++) if(lifetime[i] != -1) update(0,Q-1,lifetime[i],Q-1,1,i);
123+
clear(0,Q-1,1);
124+
for(int i=0;i<Q;i++) cout<<res[i]<<'\n';
125+
126+
}
127+
```

0 commit comments

Comments
 (0)