BZOJ3211 花神游历各国(分块 区间开根号)

题意:给n个数,可以进行两种操作:给区间[l,r]每个数开方向下取整;算区间[l,r]的和。

思路:我们可以知道,一个数一直开方下去,就会变成0或者1,然后就不会变了。那么当一个区间只剩0或1时,就不用进行操作了。那么直接分块,然后搞一个flag判断一下是否变成0。稍微优化一下。

代码:

#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 10;
const int M = maxn * 30;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int belong[maxn], block;
int flag[maxn];
ll sum[maxn];
ll a[maxn];
struct Block{
    int l, r;
}b[maxn];
void change(int l, int r){
    int bl = belong[l], br = belong[r];
    if(bl == br){
        if(!flag[bl]){
            for(int i = l; i <= r; i++){
                sum[bl] -= a[i];
                a[i] = (int)sqrt(a[i]);
                sum[bl] += a[i];
            }
            flag[bl] = 1;
            for(int j = b[bl].l; j <= b[bl].r; j++){
                if(a[j] > 1){
                    flag[bl] = 0;
                    break;
                }
            }
        }
    }
    else{
        if(!flag[bl]){
            for(int i = l; i <= b[bl].r; i++){
                sum[bl] -= a[i];
                a[i] = (int)sqrt(a[i]);
                sum[bl] += a[i];
            }
            flag[bl] = 1;
            for(int j = b[bl].l; j <= b[bl].r; j++){
                if(a[j] > 1){
                    flag[bl] = 0;
                    break;
                }
            }
        }
        for(int i = bl + 1; i <= br - 1; i++){
            if(!flag[i]){
                sum[i] = 0;
                flag[i] = 1;
                for(int j = b[i].l; j <= b[i].r; j++){
                    a[j] = (int)sqrt(a[j]);
                    sum[i] += a[j];
                    if(a[j] > 1) flag[i] = 0;
                }
            }
        }
        if(!flag[br]){
            for(int i = b[br].l; i <= r; i++){
                sum[br] -= a[i];
                a[i] = (int)sqrt(a[i]);
                sum[br] += a[i];
            }
            flag[br] = 1;
            for(int j = b[br].l; j <= b[br].r; j++){
                if(a[j] > 1){
                    flag[br] = 0;
                    break;
                }
            }
        }
    }
}

ll query(int l, int r){
    int bl = belong[l], br = belong[r];
    ll ans = 0;
    if(bl == br){
        for(int i = l; i <= r; i++){
            ans += a[i];
        }
    }
    else{
        for(int i = l; i <= b[bl].r; i++){
            ans += a[i];
        }
        for(int i = bl + 1; i <= br - 1; i++){
            ans += sum[i];
        }
        for(int i = b[br].l; i <= r; i++){
            ans += a[i];
        }
    }
    return ans;
}
int main(){
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%lld", &a[i]);
    }
    block = sqrt(n);
    for(int i = 1; i <= n; i++){
        belong[i] = (i - 1) / block + 1;
    }
    for(int i = 1; i <= belong[n]; i++){
        b[i].l = (i - 1) * block + 1;
        b[i].r = min(n, b[i].l + block - 1);
        sum[i] = flag[i] = 0;
        for(int j = b[i].l; j <= b[i].r; j++) sum[i] += a[j];
    }
    int m;
    scanf("%d", &m);
    for(int i = 1; i <= m; i++){
        int o, l, r;
        int c;
        scanf("%d%d%d", &o, &l, &r);
        if(o == 2){
            change(l, r);
        }
        else{
            printf("%lld\n", query(l, r));
        }
    }
    return 0;
}

 

posted @ 2019-05-22 00:10  KirinSB  阅读(237)  评论(0编辑  收藏  举报