1. 程式人生 > >【線段樹】 HDU 5828

【線段樹】 HDU 5828

傳送門

【題目大意】支援區間開根,區間加,區間求和。

【思路】維護區間的最大最小值。對於開根操作。如果極差==0,那麼就相當於區間加一個負數。如果極差==1,考慮開根後的極差。如果開根後極差仍為1,就還是一個區間加。如果開根後極差為0,那麼就是區間覆蓋。程式碼如下。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#define lc (root<<1)
#define rc (root<<1|1)
#define mid (T[root].l+T[root].r>>1)
#define int long long
using namespace std;
const int maxn=1e5+5;
struct node{
    int l,r,sum,maxx,minn,add,same;
}T[maxn<<2];
int n,m,op,x,y,v,t,a[maxn];
inline void read(int &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
void prin(int x){
    if(x>9) prin(x/10);
    putchar(x%10+48);
}
inline void pushup(int root){
    T[root].sum=T[lc].sum+T[rc].sum;
    T[root].maxx=max(T[lc].maxx,T[rc].maxx);
    T[root].minn=min(T[lc].minn,T[rc].minn);
}
inline void pushdown(int root){
    if(T[root].same){
        T[lc].maxx=T[lc].minn=T[lc].same=T[root].same;
        T[rc].maxx=T[rc].minn=T[rc].same=T[root].same;
        T[lc].sum=(T[lc].r-T[lc].l+1)*T[root].same;
        T[rc].sum=(T[rc].r-T[rc].l+1)*T[root].same;
        T[lc].add=T[rc].add=0;
        T[root].same=0;
    }
    if(T[root].add){
        T[lc].add+=T[root].add;
        T[rc].add+=T[root].add;
        T[lc].sum+=T[root].add*(T[lc].r-T[lc].l+1);
        T[rc].sum+=T[root].add*(T[rc].r-T[rc].l+1);
        T[lc].maxx+=T[root].add,T[rc].maxx+=T[root].add;
        T[lc].minn+=T[root].add,T[rc].minn+=T[root].add;
        T[root].add=0;
    }
}
void build(int root,int l,int r){
    T[root].l=l,T[root].r=r,T[root].add=0,T[root].same=0;
    if(l==r){
        T[root].sum=a[l];
        T[root].maxx=a[l];
        T[root].minn=a[l];
        return;
    }
    build(lc,l,mid),build(rc,mid+1,r);
    pushup(root);
}
void uptadd(int root,int L,int R,int v){
    if(L<=T[root].l&&R>=T[root].r){
        T[root].add+=v;        
        T[root].sum+=(T[root].r-T[root].l+1)*v;
        T[root].maxx+=v;
        T[root].minn+=v;
        return;
    }
    pushdown(root);
    if(L<=mid) uptadd(lc,L,R,v);
    if(R> mid) uptadd(rc,L,R,v);
    pushup(root);
}

void uptsqrt(int root,int L,int R){
    if(L<=T[root].l&&R>=T[root].r){
        if(T[root].maxx==1) return;
        if(T[root].l==T[root].r){
            T[root].sum=T[root].maxx=T[root].minn=floor(sqrt(T[root].sum));
            return;
        }
        if(T[root].maxx==T[root].minn){
            int now=floor(sqrt(T[root].maxx));
            T[root].add+=now-T[root].maxx;
            T[root].sum=(T[root].r-T[root].l+1)*now;
            T[root].maxx=T[root].minn=now;
            return;
        }
        if(T[root].maxx-T[root].minn==1){
            int Tmpb=T[root].maxx;int Tmps=T[root].minn;
            int pos=T[root].sum-T[root].minn*(T[root].r-T[root].l+1);
            T[root].maxx=floor(sqrt(T[root].maxx));
            T[root].minn=floor(sqrt(T[root].minn));
            if(T[root].maxx-T[root].minn==1){
                T[root].add+=T[root].maxx-Tmpb;
                T[root].sum=T[root].maxx*pos+T[root].minn*(T[root].r-T[root].l+1-pos);
            }
            else{
                T[root].add=0,T[root].same=T[root].maxx;
                T[root].sum=T[root].maxx*(T[root].r-T[root].l+1);
            }
            return;
        }
    }
    pushdown(root);
    if(L<=mid) uptsqrt(lc,L,R);
    if(R> mid) uptsqrt(rc,L,R);
    pushup(root);
}
int query(int root,int L,int R){
    if(L<=T[root].l&&R>=T[root].r) return T[root].sum;
    pushdown(root);    
    int ret=0;
    if(L<=mid) ret+=query(lc,L,R);
    if(R>mid)  ret+=query(rc,L,R);
    return ret;
}
signed main(){
    read(t);
    while(t--){
        read(n),read(m);
        for(int i=1;i<=n;++i) read(a[i]);
        build(1,1,n);
        while(m--){
            read(op),read(x),read(y);
            if(op==1) read(v),uptadd(1,x,y,v);
            if(op==2) uptsqrt(1,x,y);
            if(op==3) prin(query(1,x,y)),putchar('\n');
        }
    }
}