牛客国庆day3 Grid [线段树]

50 篇文章 0 订阅
3 篇文章 0 订阅

Bobo has n*m points arranged into a matrix with n rows and m columns. The points in the intersection of the i-th row and the j-th column is labeled with (i, j).
He is going to perform q operations of the following 2 kinds.
1. Given parameters a, b, add edges between points (i, j) and (i, j + 1) for all a<=i<=b and 1<=j<m.
2. Given parameters a, b, add edges between points (i, j) and (i + 1, j) for all  1<=j<n and a<=j<=b.
Bobo would like to know the number of connected components after each operation.

题意:初始n*m个单元各自为联通快,每次有两种操作,将a<=i<=b的每一行连成一个联通快,或将a<=j<=b的每一列连成一个联通快,每次操作询问联通快的个数

题解:

显然如果只有1或只有2操作,则联通快的数量就是:没有被整行整列连起来的联通快数量+整行整列被连起来的行或列的数量

如果既有1和2,则这些被整行整列连起来的行和列变成一个联通快,联通快的数量等于:原先联通快的数量(n*m)-被整行整列连起来的块+1

显然,我们只需要一共有多少行或列被整行连起来,重复连只能算一次,我们用线段树分别维护行和列,则问题转化为线段涂色问最后有多少黑色块的问题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
const ll maxn=3e5+7;
const ll maxm=5e5+7;
const ll modn=1e9+7;
const ll mod=1e9+7;
const ll inf=1e18;
inline ll lowbit(ll x){return x&-x;}
inline ll CountOneBinary(ll num){ll ans=0;while(num){if(num&1) ans+=1;num>>=1;}return ans;}
inline ll read(ll &x){char c;x=0;for(c=getchar();c>'9'||c<'0';c=getchar());for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';return x;}
inline ll qp(ll x,ll y){ll ans=1;while(y){if(y&1) ans=ans*x%modn;x=x*x%modn;y>>=1;}return ans;}
inline double qp(double x,ll y){double ans=0;while(y){if(y&1) ans=ans*x;x=x*x;y>>=1;}return ans;}
ll n,m,Q;
struct query
{
    ll op,l,r;
}q[maxn];
ll xx[maxn*2],totx,cnx;
ll yy[maxn*2],toty,cny;
ll sum[3][maxn*8],val[3][maxn*8];
void pushup(ll id,ll rt)
{
    val[id][rt]=val[id][rt*2]+val[id][rt*2+1];
}
void pushdown(ll id,ll rt)
{
    val[id][rt*2]=sum[id][rt*2];
    val[id][rt*2+1]=sum[id][rt*2+1];
}
void buildx(ll id,ll rt,ll l,ll r)
{
    val[id][rt]=0;
    if(l>r) return;
    if(l==r)
    {
        sum[id][rt]=xx[l+1]-xx[l];
        return;
    }
    ll mid=(l+r)/2;
    buildx(id,rt*2,l,mid);
    buildx(id,rt*2+1,mid+1,r);
    sum[id][rt]=sum[id][rt*2]+sum[id][rt*2+1];
}
void buildy(ll id,ll rt,ll l,ll r)
{
    val[id][rt]=0;
    if(l>r) return;
    if(l==r)
    {
        sum[id][rt]=yy[l+1]-yy[l];
        return;
    }
    ll mid=(l+r)/2;
    buildy(id,rt*2,l,mid);
    buildy(id,rt*2+1,mid+1,r);
    sum[id][rt]=sum[id][rt*2]+sum[id][rt*2+1];
}
void update(ll id,ll rt,ll l,ll r,ll ql,ll qr)
{
    if(ql<=l&&r<=qr)
    {
        val[id][rt]=sum[id][rt];
        return;
    }
    if(val[id][rt]==sum[id][rt]) pushdown(id,rt);
    ll mid=(l+r)/2;
    if(ql<=mid)
        update(id,rt*2,l,mid,ql,qr);
    if(qr>mid)
        update(id,rt*2+1,mid+1,r,ql,qr);
    pushup(id,rt);
}
int main()
{
    while(scanf("%lld%lld%lld",&n,&m,&Q)==3)
    {
        cnx=cny=0;
        for(ll i=1;i<=Q;i++)
        {
            scanf("%lld%lld%lld",&q[i].op,&q[i].l,&q[i].r);
            if(q[i].op==1)
            {
                xx[++cnx]=q[i].l;
                xx[++cnx]=q[i].r+1;
            }
            if(q[i].op==2)
            {
                yy[++cny]=q[i].l;
                yy[++cny]=q[i].r+1;
            }
        }
        sort(xx+1,xx+cnx+1);
        sort(yy+1,yy+cny+1);
        totx=unique(xx+1,xx+cnx+1)-xx-1;
        toty=unique(yy+1,yy+cny+1)-yy-1;
        xx[totx+1]=n+1;
        yy[toty+1]=m+1;
//        cout<<totx<<" "<<toty<<endl;
//        cout<<"bug"<<endl;
        buildx(1,1,1,totx);
        buildy(2,1,1,toty);
//        for(int i=1;i<=10;i++)
//        {
//            cout<<sum[1][i]<<" ";
//        }
//        cout<<endl;
        for(ll i=1;i<=Q;i++)
        {
            if(q[i].op==1)
            {
                q[i].l=lower_bound(xx+1,xx+totx+1,q[i].l)-xx;
                q[i].r=lower_bound(xx+1,xx+totx+1,q[i].r+1)-xx;
                update(1,1,1,totx,q[i].l,q[i].r-1);
                //cout<<q[i].l<<" "<<q[i].r-1<<endl;
            }
            else
            {
                q[i].l=lower_bound(yy+1,yy+toty+1,q[i].l)-yy;
                q[i].r=lower_bound(yy+1,yy+toty+1,q[i].r+1)-yy;
                update(2,1,1,toty,q[i].l,q[i].r-1);
            }
            ll r=val[1][1];
            ll c=val[2][1];
            //cout<<r<<":"<<c<<endl;
            ll ans=0;
            if(r==0&&c==0) ans=0;
            else if(r==0&&c!=0) ans=1LL*(m-c)*n+c;
            else if(r!=0&&c==0) ans=1LL*(n-r)*m+r;
            else ans=1LL*n*m-(1LL*r*m+1LL*c*n-1LL*r*c)+1;
            printf("%lld\n",ans);
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值