[BZOJ3211]花神游历各国

线段树题,打个标记即可,因为如果那个位置的值被降到了1/0,再怎么sqrt它也不会变。如果一个节点的两个子树已经全部被打了标记,那么就不用再更新了。
这份代码因为一开始打错了疯狂T,加了各种鬼畜优化。。。(貌似这的跑的能快一点点)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cctype>
#include <cstring>
const int N=100005;
typedef long long ll;
struct Segtree {
    ll l,r,sum;
    bool flag;
} t[N<<2];
ll a[N],n,m;
ll rd() {
    ll x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x;
}
void pushup(int cur) {
    cur[t].sum=(cur<<1)[t].sum+(cur<<1|1)[t].sum;
    cur[t].flag=(cur<<1)[t].flag&(cur<<1|1)[t].flag;
}
void build(int cur,int l,int r) {
    cur[t].l=l;
    cur[t].r=r;
    if(l==r) {
        cur[t].sum=rd();
        if(cur[t].sum==1||cur[t].sum==0) cur[t].flag=1;
        return;
    }
    int mid=l+r>>1;
    build(cur<<1,l,mid);
    build(cur<<1|1,mid+1,r);
    pushup(cur);
}
void update(int l,int r,int cur) {
    if(cur[t].flag) return;
    if(cur[t].l==cur[t].r) {
        cur[t].sum=(ll)sqrt(cur[t].sum);
        if(t[cur].sum==1||cur[t].sum==0) cur[t].flag=1;
        return;
    }
    int mid=cur[t].l+cur[t].r>>1;
    if(l>mid) update(l,r,cur<<1|1);
    else if(r<=mid) update(l,r,cur<<1);
    else update(l,mid,cur<<1),update(mid+1,r,cur<<1|1);
    pushup(cur);
}
ll query(int l,int r,int cur) {
    if(cur[t].l>=l&&r>=cur[t].r)return cur[t].sum;
    int mid=cur[t].l+cur[t].r>>1;
    if(mid>=r) return query(l,r,cur<<1);
    else if(l>mid) return query(l,r,cur<<1|1);
    else return query(l,mid,cur<<1)+query(mid+1,r,cur<<1|1);
}
int main() {
    scanf("%d",&n);
    build(1,1,n);
    scanf("%d",&m);
    int opt,l,r;
    while(m--) {
        opt=rd();l=rd();r=rd();
        if(l>r) std::swap(l,r);
        if(opt==1)
            printf("%lld\n",query(l,r,1));
        else update(l,r,1);
    }
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9301521.html