1. 程式人生 > >[BZOJ3211]花神遊歷各國

[BZOJ3211]花神遊歷各國

wap () \n 操作 += 結構 直接 spa lse

題目鏈接:

傳送門

題目分析:

題意簡化:給你一個元素非負的序列,要求支持區間開方,區間求和。

做法很多,洛谷的題解裏線段樹/樹狀數組/分塊/...都有(基本就是數據結構的群魔亂舞),不過分塊能跑過的話分塊就好了。
記錄區間\(i\)的元素總和為\(sum_i\),如果\(sum_i=R[i]-L[i]+1\)的話說明這個區間內只有1了,就不用再操作了,否則直接暴力開方即可。
由於數據範圍很小,最多開個10次方上下就全都變成1了,所以時間上是沒有問題的。
再有一個細節要處理是數據可能包含0(這一點洛谷保證沒有0的數據範圍頓時變得一萬個良心),所以在讀入的時候如果讀到0就把這個元素加成1,並另外維護一個數組記錄此元素的位置,再維護一個數組記錄每個塊內0的個數,最後求和的時候減去即可。
數據範圍很大,不開\(long long\)

跑不過。

代碼:

#include<bits/stdc++.h>
#define N (200000+5)
using namespace std;
inline long long read(){
    long long cnt=0,f=1;char c;
    c=getchar();
    while(!isdigit(c)){
        if(c==‘-‘) f=-f;
        c=getchar();
    }
    while(isdigit(c)){
        cnt=cnt*10+c-‘0‘;
        c=getchar();
    }
    return cnt*f;
}
long long n,m,k,l,r;
long long a[N],sum[N];
long long L[N],R[N],pos[N];
long long pos_of_zero[N],sum_of_zero[N];
void Sqrt(int l,int r) {
    int p=pos[l];int q=pos[r];
    if(p==q) {
        if(sum[p]==R[p]-L[p]+1) return;
        else {
            for(register int i=l;i<=r;i++) {
                sum[p]-=a[i];
                a[i]=sqrt(a[i]);
                sum[p]+=a[i];
            }
        }
    }
    else {
        if(sum[p]>R[p]-L[p]+1) {
            for(register int i=l;i<=R[p];i++) {
                sum[p]-=a[i];
                a[i]=sqrt(a[i]);
                sum[p]+=a[i];
            }
        }
        if(sum[q]>R[q]-L[q]+1) {
            for(register int i=L[q];i<=r;i++) {
                sum[q]-=a[i];
                a[i]=sqrt(a[i]);
                sum[q]+=a[i];
            }
        }
        for(register int i=p+1;i<=q-1;i++) {
            if(sum[i]==R[i]-L[i]+1) continue;
            else {
                for(register int j=L[i];j<=R[i];j++) {
                    sum[i]-=a[j];
                    a[j]=sqrt(a[j]);
                    sum[i]+=a[j];
                }
            }
        }
    }
}
long long query(int l,int r) {
    int p=pos[l];int q=pos[r];
    long long ans = 0;
    if(p==q) {
        for(register int i=l;i<=r;i++) {
            ans+=a[i];ans-=pos_of_zero[i];
        }
    }
    else {
        for(register int i=l;i<=R[p];i++) {
            ans+=a[i];ans-=pos_of_zero[i];
        }
        for(register int i=L[q];i<=r;i++) {
            ans+=a[i];ans-=pos_of_zero[i];
        }
        for(register int i=p+1;i<=q-1;i++) {
            ans+=sum[i];ans-=sum_of_zero[i];
        }
    }
    return ans;
}
int main(){
    n=read();
    for(register int i=1;i<=n;i++) {
        a[i]=read();
        if(a[i]==0) {
            pos_of_zero[i]=1;
            a[i]++;
        }
    }
    int t=sqrt(n);
    for(register int i=1;i<=t;i++){
        L[i]=(i-1)*t+1;
        R[i]=i*t;
    }
    if(R[t]<n) {
        ++t;
        L[t]=R[t-1]+1;
        R[t]=n;
    }
    for(register int i=1;i<=t;i++)
        for(register int j=L[i];j<=R[i];j++){
            pos[j]=i;
            sum[i]+=a[j];
            if(pos_of_zero[j]) sum_of_zero[i]++;
        }
    m=read();
    for(register int i=1;i<=m;i++) {
        k=read();l=read();r=read();
        if(l>r) swap(l,r);
        if(k==2) Sqrt(l,r);
        else printf("%lld\n",query(l,r));
    }
    return 0;
}

[BZOJ3211]花神遊歷各國