给出一个
n
×
m
n×m
n×m,
n
,
m
≤
1
e
9
n,m\leq1e9
n,m≤1e9的矩形。一开始,矩形中的每个点都不连通。然后有
q
≤
1
e
5
q\leq1e5
q≤1e5的操作,每次操作都会把
[
l
,
r
]
[l,r]
[l,r]行或者
[
l
,
r
]
[l,r]
[l,r]列全部连接起来,求问对于每一次操作之后的连通块的个数是多少。
对于每次询问,如果只连接了行或者列的话。以连接了
x
x
x行为例,那么总共有
n
m
−
x
(
m
−
1
)
nm-x(m-1)
nm−x(m−1)个连通块。如果连接了
x
x
x行,
y
y
y列的话,则可以看作是中间的一个交叉的图形形成
1
1
1个连通块,其余剩下的是若干个孤立的点,答案是
(
n
−
x
)
(
m
−
y
)
+
1
(n-x)(m-y)+1
(n−x)(m−y)+1。
询问连接了多少个行列,可以用线段树维护。由于
n
,
m
n,m
n,m比较大,所以需要动态开点。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
static const int maxn = 100010;
static const int INF = 0x3f3f3f3f;
static const int mod = (int)1e9 + 7;
static const double eps = 1e-6;
static const double pi = acos(-1);
void redirect(){
#ifdef LOCAL
freopen("test.txt","r",stdin);
#endif
}
const int N=2e5+7;
struct SegTree {
int sum[4*N];
int ls[4*N],rs[4*N];
int tot=0;
void clear() { tot=0; }
void modify(int &rt,int l,int r,int L,int R) {
if(rt==0) rt=++tot;
if(sum[rt]==r-l+1) return;
sum[rt]=r-l+1;
if(L<=l&&r<=R) return;
int mid=(l+r)>>1;
if(L<=mid) modify(ls[rt],l,mid,L,R);
if(R>=mid+1) modify(rs[rt],mid+1,r,L,R);
sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
}row,col;
int main(){
int n,m,q;
while(scanf("%d%d%d",&n,&m,&q)!=EOF) {
int opt,l,r;
int rt1=0,rt2=0;
row.clear();col.clear();
int R=0,C=0;
while(q--) {
scanf("%d%d%d",&opt,&l,&r);
if(opt==1) ++R,row.modify(rt1,1,n,l,r);
else if(opt==2) ++C,col.modify(rt2,1,m,l,r);
if(R&&C) printf("%lld\n",1LL*(n-row.sum[1])*(m-col.sum[1])+1);
else if(R) printf("%lld\n",1LL*n*m-1LL*row.sum[1]*(m-1));
else if(C) printf("%lld\n",1LL*n*m-1LL*col.sum[1]*(n-1));
}
for(int i=1;i<=row.tot;i++)
row.sum[i]=row.ls[i]=row.rs[i]=0;
for(int i=1;i<=col.tot;i++)
col.sum[i]=col.ls[i]=col.rs[i]=0;
}
return 0;
}