分块入门题

分块入门题5:

给[L,R]取开方,一个数字最多被取开方6次,那么一个块内有需要开方的时候才对这个块取开方,那么最多6*n*sqrt(n)次,分块直接写

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int l[5500],r[5500],belong[105000];
int q1[105000],q2[105000];
int is[5005],mark[5005];
int n,block,num;
ll sum1[5005];
void build(){
	double f1=n;
	block=sqrt(f1);
	if(block==0)block=1;
	num=n/block;if(n%block!=0)num++;
	int i;
	for(i=1;i<=n;i++){
	belong[i]=(i-1)/block+1;
    is[belong[i]]+=6; //is表示的是这个里面的块数,6次就不再sqrt了
	sum1[belong[i]]+=q1[i];
	}
	for(i=1;i<=num;i++){ //i表示这一个块l[i],r[i]
		l[i]=(i-1)*block+1;
		r[i]=min(n,i*block); //每个block个边界,是包括的
	}//这里为第i块的左区间与右区间
}
int modify(int x,int y,int t){
	int i,res=0,ans=0;
	if(belong[x]==belong[y]){
		for(i=x;i<=y;i++){
            sum1[belong[i]]-=q1[i]-sqrt(q1[i]);
            q1[i]=sqrt(q1[i]);
            if(q2[i]<6){//最多修改6次
            q2[i]++;
            is[belong[i]]--;
            }
		}
		if(is[belong[x]]==0)mark[x]=1;
	}else{
		for(i=x;i<=r[belong[x]];i++){
            sum1[belong[i]]-=q1[i]-sqrt(q1[i]);
            q1[i]=sqrt(q1[i]);
            if(q2[i]<6){//最多修改5次
            q2[i]++;
            is[belong[i]]--;
            }
		}
		if(is[belong[x]]==0)mark[x]=1;

		for(i=l[belong[y]];i<=y;i++){
            sum1[belong[i]]-=q1[i]-sqrt(q1[i]);
            q1[i]=sqrt(q1[i]);
            if(q2[i]<6){//最多修改5次
            q2[i]++;
            is[belong[i]]--;
            }
		}
		if(is[belong[y]]==0)mark[y]=1;

		int left1,right1,mid1;
		for(i=belong[x]+1;i<belong[y];i++){//
            if(mark[i]==0){
                for(int j=l[i];j<=r[i];j++){
                    sum1[i]-=q1[j]-sqrt(q1[j]);
                    q1[j]=sqrt(q1[j]);
                    if(q2[j]<6){//最多修改5次
                    q2[j]++;
                    is[i]--;
                    }
                }
                if(is[i]==0)mark[i]=1;
            }
		}
	}
}
int res;
ll cnt;
int find1(int x,int y){
    int i,ans;
    if(belong[x]==belong[y]){
		for(i=x;i<=y;i++)
            cnt+=q1[i];
	}else{
		for(i=x;i<=r[belong[x]];i++)
			cnt+=q1[i];
		for(i=l[belong[y]];i<=y;i++)
			cnt+=q1[i];
		int left1,right1,mid1;
        for(i=belong[x]+1;i<belong[y];i++){
            cnt+=sum1[i];
		}
	}
}
int main(){
	//freopen("in.txt","r",stdin);
	//freopen("out1.txt","w",stdout);
	int i,k,j,f1,f2,f3,f4,t1,t2,t3,t4,l2,m;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	scanf("%d",&q1[i]);
	build();
	for(i=1;i<=n;i++){
        scanf("%d %d %d %d",&t1,&t2,&t3,&t4);
		if(t1==0){ //查询[t2,t3]全部+t4
        modify(t2,t3,t4);
		}else{
        cnt=0;
        find1(t2,t3); //比其小的最大元素
        printf("%d\n",cnt);
		}
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值