BZOJ 3211 花神游历各国 线段树

BZOJ 3211 花神游历各国 线段树

各数根号之和无法合并,无法用线段树维护,只能暴力开根号(毒瘤)。但是又注意到\(10^9\)级别的数开方次数不超过10,任何数(除\(0\))开到最后都为\(1\),并且后续修改操作并不会再修改值,所以维护区间和,区间正常查询,区间递归到每一个数暴力修改,修改后检查并标记一下无法再被修改的区间,下一次修改时直接跳过。

注意:后续修改对\(0\)也无效,所以\(0\)\(1\)到要标记(否则\(T\)到50)

#include <cstdio>
#include <cmath>
#define ll long long
#define sl (x<<1)
#define sr (x<<1|1)
#define MAXN 100010
using namespace std;
struct nod{
    int l; int r;
    ll lazy; ll val;
    bool over;
} tre[MAXN*4];
int a[MAXN];
int s[MAXN][10];
int n;
void buildt(int l, int r, int x){
    tre[x].l=l;
    tre[x].r=r;
    tre[x].over=0;
    if(l==r){
        tre[x].val=a[l];
        return;
    }
    int mid=(l+r)>>1;
    buildt(l, mid, sl);
    buildt(mid+1, r, sr);
    tre[x].val=tre[sl].val+tre[sr].val;
    tre[x].over=tre[sl].over&&tre[sr].over;
}
void change(int x, int cl, int cr){
    if(tre[x].over) return;
    if(tre[x].l==tre[x].r){
        tre[x].val=sqrt(tre[x].val);
        if(tre[x].val==1||tre[x].val==0) tre[x].over=1;
        return;
    }
    int mid=(tre[x].l+tre[x].r)>>1;
    if(cl<=mid) change(sl, cl, cr);
    if(cr>mid) change(sr, cl, cr);
    tre[x].val=tre[sl].val+tre[sr].val;
    tre[x].over=tre[sl].over&&tre[sr].over;
}
ll query(int x, int ql, int qr){
    if(ql<=tre[x].l&&tre[x].r<=qr){
        return tre[x].val;
    }
    int mid=(tre[x].l+tre[x].r)>>1;
    ll ans=0;
    if(ql<=mid) ans+=query(sl, ql, qr);
    if(qr>mid) ans+=query(sr, ql, qr);
    return ans;
}
int main()
{
    scanf("%d", &n);
    for(int i=1;i<=n;++i)
        scanf("%d", &a[i]);
    buildt(1,n,1);
    int m;
    scanf("%d", &m);
    while(m--){
        int x,l,r;
        scanf("%d %d %d", &x, &l, &r);
        if(x==1) printf("%lld\n", query(1,l,r));
        else change(1, l, r);
    }
    return 0;
}
posted @ 2019-07-11 14:54  Santiego  阅读(102)  评论(0编辑  收藏  举报