HDU 5828 Rikka with Sequence(线段树)

 

【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=5828

 

【题目大意】

  给出一个数列,要求支持区间加法,区间开方和区间和查询操作。

 

【题解】

  考虑开方后会出现成片相同的数字,因此我们在每个区间额外维护区间内数字是否相同的tag,如果区间内数字均相同,那么开方就可以转化为减法的标记,即t=sqrt(t)转化为tag=sqrt(t)-t。剩下就是简单的标记维护了。

 

【代码】

#include <cstdio>
#include <algorithm>
#include <cmath> 
using namespace std; 
const int N=2000000;
struct node{int l,r,f,a,b;long long tag,max,val;}T[N];
int cas,tot,n,m,l,r,c,op,num;
void addtag(int x,int tag){
    T[x].tag+=tag;
    T[x].max+=tag;
    T[x].val+=(long long)tag*(T[x].b-T[x].a+1);
}
void pb(int x){
    if(T[x].l){addtag(T[x].l,T[x].tag);addtag(T[x].r,T[x].tag);}
    T[x].tag=0;
}
void up(int x){
    T[x].max=max(T[T[x].l].max,T[T[x].r].max);
    T[x].val=T[T[x].l].val+T[T[x].r].val;
    if(T[T[x].l].f&&T[T[x].r].f&&T[T[x].l].max==T[T[x].r].max)T[x].f=1;
    else T[x].f=0;
}
void build(int l,int r){
    int x=++tot;
    T[x].a=l;T[x].b=r;T[x].f=0;
    T[x].tag=T[x].l=T[x].r=T[x].max=T[x].val=0;
    if(l==r){T[x].f=1;scanf("%lld",&T[x].val);T[x].max=T[x].val;return;}
    int mid=(l+r)>>1;
    T[x].l=tot+1;build(l,mid);
    T[x].r=tot+1;build(mid+1,r);
    up(x);
}
void change(int x,int a,int b,int p){
    if(T[x].a>=a&&T[x].b<=b){addtag(x,p);return;}
    if(T[x].tag)pb(x); int mid=(T[x].a+T[x].b)>>1;
    if(mid>=a&&T[x].l)change(T[x].l,a,b,p);
    if(mid<b&&T[x].r)change(T[x].r,a,b,p);up(x);
}
long long query_sum(int x,int a,int b){
    if(T[x].a>=a&&T[x].b<=b)return T[x].val;
    if(T[x].tag)pb(x);int mid=(T[x].a+T[x].b)>>1;long long res=0;
    if(mid>=a&&T[x].l)res+=query_sum(T[x].l,a,b);
    if(mid<b&&T[x].r)res+=query_sum(T[x].r,a,b); 
    return res;
}
void Tsqrt(int x,int a,int b){
    if(T[x].a>=a&&T[x].b<=b){
        if(T[x].f){
            long long t=T[x].max;
            t=sqrt(t);
            addtag(x,t-T[x].max);
            return;
        }
    }if(T[x].tag)pb(x); int mid=(T[x].a+T[x].b)>>1;
    if(mid>=a&&T[x].l)Tsqrt(T[x].l,a,b);
    if(mid<b&&T[x].r)Tsqrt(T[x].r,a,b);up(x);
}
int main(){
    scanf("%d",&cas);
    while(cas--){
        scanf("%d%d",&n,&m);
        build(1,n);tot=0;
        while(m--){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%d",&l,&r,&num);
                change(1,l,r,num);
            }else if(op==2){
                scanf("%d%d",&l,&r);
                Tsqrt(1,l,r);
            }else{
                scanf("%d%d",&l,&r);
                printf("%lld\n",query_sum(1,l,r));
            }
        }
    }return 0;
}

  

posted @ 2016-11-17 18:52  forever97  阅读(399)  评论(0编辑  收藏  举报