LibreOj 6281数列ブロック入門5区間開方+区間和

29761 ワード

数列ブロック入門4
リンク:LibreOj 6281
タイトルの説明
長さnの数列とnの操作を与え,操作は区間開方,区間求和に関連する.
入力フォーマット
1行目にnという数字を入力します.
2行目にはn個の数字を入力し、i番目の数字はa[i]で、スペースで区切ります.
次にn行の質問を入力し、各行に4つの数字op、l、r、cを入力してスペースで区切ります.
op=0の場合、[l,r]の間の数字をすべて開方する(sqrtは下に整列する)
op=1の場合、[l,r]のすべての数字の和を表す
出力フォーマット
質問のたびに、1行1つの数字を出力して答えを表します.
サンプル入力
4 1 2 2 3 0 1 3 1 1 1 4 4 0 1 2 2 1 1 2 4
サンプル出力
6 2
分析:
開方は操作が難しく、区間とsumについて、区間の各値が開方されている場合は、すべての値を1回加算しなければ区間とを更新できません.しかし、0ではない数字が何度も開くと必ず1になります.遍歴するときは1か0であれば直接スキップすると判断します.1と0は開方が変わらないからです.1つの配列markタグ区間がすべて0と1であるかどうかを開き、検索時に区間がすべて0と1であると判断すると、直接1つの区間をスキップすることができます.
マイコード:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=5e4+5;
int l[maxm],r[maxm];
int a[maxm],sum[maxm];
int belong[maxm];
int mark[maxm];
int block,num;
int n;
void build(){
    block=sqrt(n);
    num=n/block;
    if(n%block)num++;
    for(int i=1;i<=num;i++){
        l[i]=(i-1)*block+1;
        r[i]=i*block;
        sum[i]=0;
        mark[i]=0;//   mark
    }
    r[num]=n;
}
void pd(int x){
    for(int i=l[x];i<=r[x];i++){
        if(a[i]>1){
            return ;
        }
    }
    mark[x]=1;
}
void update(int x,int y){
    if(belong[x]==belong[y]){
        if(mark[belong[x]]){
            return ;
        }
        for(int i=x;i<=y;i++){
            if(a[i]<=1){
                continue;
            }
            sum[belong[i]]-=a[i]-sqrt(a[i]);//     
            a[i]=sqrt(a[i]);
        }
        pd(belong[x]);//        mark  
        return ;
    }
    for(int i=x;i<=r[belong[x]];i++){
        if(a[i]<=1)continue;
        sum[belong[i]]-=a[i]-sqrt(a[i]);
        a[i]=sqrt(a[i]);
    }
    pd(belong[x]);
    for(int i=l[belong[y]];i<=y;i++){
        if(a[i]<=1)continue;
        sum[belong[i]]-=a[i]-sqrt(a[i]);
        a[i]=sqrt(a[i]);
    }
    pd(belong[y]);
    for(int i=belong[x]+1;i<belong[y];i++){
        if(mark[i])continue;
        for(int j=l[i];j<=r[i];j++){
            if(a[j]<=1)continue;
            sum[belong[j]]-=a[j]-sqrt(a[j]);
            a[j]=sqrt(a[j]);
        }
        pd(i);
    }
}
int ffind(int x,int y){
    int ans=0;
    if(belong[x]==belong[y]){
        for(int i=x;i<=y;i++){
            ans+=a[i];
        }
        return ans;
    }
    for(int i=x;i<=r[belong[x]];i++){
        ans+=a[i];
    }
    for(int i=l[belong[y]];i<=y;i++){
        ans+=a[i];
    }
    for(int i=belong[x]+1;i<belong[y];i++){
        ans+=sum[i];
    }
    return ans;
}
int main(){
    scanf("%d",&n);
    build();
    for(int i=1;i<=n;i++){
        belong[i]=(i-1)/block+1;
        scanf("%d",&a[i]);
        sum[belong[i]]+=a[i];
    }
    for(int i=1;i<=n;i++){
        int d,x,y,c;
        scanf("%d%d%d%d",&d,&x,&y,&c);
        if(d==0){
            update(x,y);
        }else{
            printf("%d
"
,ffind(x,y)); } } return 0; }