[2018HNCPC] E Grid 线段树

给出一个 n × m n×m n×m n , m ≤ 1 e 9 n,m\leq1e9 n,m1e9的矩形。一开始,矩形中的每个点都不连通。然后有 q ≤ 1 e 5 q\leq1e5 q1e5的操作,每次操作都会把 [ l , r ] [l,r] [l,r]行或者 [ l , r ] [l,r] [l,r]列全部连接起来,求问对于每一次操作之后的连通块的个数是多少。
对于每次询问,如果只连接了行或者列的话。以连接了 x x x行为例,那么总共有 n m − x ( m − 1 ) nm-x(m-1) nmx(m1)个连通块。如果连接了 x x x行, y y y列的话,则可以看作是中间的一个交叉的图形形成 1 1 1个连通块,其余剩下的是若干个孤立的点,答案是 ( n − x ) ( m − y ) + 1 (n-x)(m-y)+1 (nx)(my)+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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值