【線段樹】 HDU 5828
阿新 • • 發佈:2018-12-17
【題目大意】支援區間開根,區間加,區間求和。
【思路】維護區間的最大最小值。對於開根操作。如果極差==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'); } } }