Bobo has 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);
}
}
}

本文介绍了一种解决矩阵中联通快数量变化的算法。通过线段树维护行和列的连通状态,处理两种操作:一是将指定行内所有元素连成一个联通快,二是将指定列内所有元素连成一个联通快。每次操作后,算法都能快速计算出当前矩阵中的联通快总数。
349

被折叠的 条评论
为什么被折叠?



