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; }
愿你出走半生,归来仍是少年