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
", query(1,l,r));
        else change(1, l, r);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/santiego/p/11169986.html