P3870 [TJOI2009]开关(分块)

本文详细介绍了分块优化算法在解决区间操作问题上的应用。通过对比两种不同的分块实现方式,解释了如何正确地进行分块,并给出了具体的代码示例。文章还展示了如何通过分块来加速区间修改和查询的操作。

P3870 [TJOI2009]开关

注意

  • 不能把块数和块大小弄混了
void block(){//这是错的
    t=sqrt(n);//这里t既是块数,也是块大小,所以就错了
    for(ri i=1;i<=t;++i)
        l[i]=(i-1)*t+1,r[i]=i*t;
    if(r[t]<n) l[++t]=r[t-1]+1,r[t]=n;
    for(ri i=1;i<=t;++i)
        for(ri j=l[i];j<=r[i];++j)
            b[j]=i;
}
/****************************************************/
void block(){//这是对的
    t=sqrt(n);
    for(ri i=1;i<=n;++i) b[i]=(i-1)/t+1;
    for(ri i=1;i<=b[n];++i) 
        l[i]=(i-1)*t+1,r[i]=i*t;
    r[b[n]]=min(r[b[n]],n);
}

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#define ri register int
using namespace std;
const int maxn=1e5+9;
int sum[maxn],f[maxn];
int l[maxn],r[maxn];//每块的端点 
int a[maxn],b[maxn];
int n,m,tot,sq;
inline int read(){//快读 
	int x=0,f1=0;char c=getchar();
	while(c>'9'||c<'0') f1=c=='-',c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();
	return f1?-x:x;
}
void block(){//分块 
	sq=sqrt(n);//sq为块长,b[n]为块数 
	for(ri i=1;i<=n;++i) b[i]=(i-1)/sq+1;
	for(ri i=1;i<=b[n];++i) 
		l[i]=(i-1)*sq+1,r[i]=i*sq;
	r[b[n]]=min(r[b[n]],n);
}
void change(int x,int y){//修改 
	int p=b[x],q=b[y];
	for(ri i=x;i<=min(y,r[p]);++i)//左边小块 
		sum[p]+=(a[i]^f[p]^1)-(a[i]^f[p]),a[i]^=1;
	if(p!=q) 
		for(ri i=l[q];i<=y;++i)//右边小块 
			sum[p]+=(a[i]^f[p]^1)-(a[i]^f[p]),a[i]^=1;
	for(ri i=p+1;i<=q-1;++i)//中间大整块 
		sum[i]=r[i]-l[i]+1-sum[i],f[i]^=1;
}
void query(int x,int y){
	int p=b[x],q=b[y],ans=0;
	for(ri i=x;i<=min(y,r[p]);++i) ans+=(a[i]^f[p]);
	if(p!=q) for(ri i=l[q];i<=y;++i) ans+=(a[i]^f[q]);
	for(ri i=p+1;i<q;++i) ans+=sum[i];
	printf("%d\n",ans);
}
int main(){
	n=read(),m=read();
	block();
	while(m--)
	{
		int op=read(),x=read(),y=read();
		if(!op) change(x,y);
		if(op) query(x,y);
	}
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Robin_w2321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值