2016暑假多校联合---Rikka with Sequence (线段树)
Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:
Yuta has an array A with n numbers. Then he makes m operations on it.
There are three type of operations:
1 l r x : For each i in [l,r], change A[i] to A[i]+x
2 l r : For each i in [l,r], change A[i] to ⌊A−−√[i]⌋
3 l r : Yuta wants Rikka to sum up A[i] for all i in [l,r]
It is too difficult for Rikka. Can you help her?
Input
The first line contains a number t(1<=t<=100), the number of the testcases. And there are no more than 5 testcases with n>1000.
For each testcase, the first line contains two numbers n,m(1<=n,m<=100000). The second line contains n numbers A[1]~A[n]. Then m lines follow, each line describe an operation.
It is guaranteed that 1<=A[i],x<=100000.
Output
For each operation of type 3, print a lines contains one number -- the answer of the query.
Sample Input
1
5 5
1 2 3 4 5
1 3 5 2
2 1 4
3 2 4
2 3 5
3 1 5
Sample Output
5
6
Author
学军中学
Source
2016 Multi-University Training Contest 8
Recommend
wange2014 | We have carefully selected several similar problems for you: 5831 5830 5829 5827 5826
题意: 三种操作,1、区间上加上一个数;
2、区间上所有数开根号向下取整;
3、区间求和;
思路: 对于记录区间的最大值和最小值,如果相等的话,那么只需要对一个数开根号,算出开根号前后的差值,这样区间开根号就变成了区间减去一个数了;
由于是开根,所以存在两个数刚开始差为1,加上某数再开根依旧是差1,这样维护相同数区间的就没用了
比如(2,3) +6-->(8,9)开根-->(2,3)如果全是这样的操作,即使维护相同的数,每次开根的复杂度都是O(N),不T才怪
这样只需要维护区间最大值最小值,当差1的时候,看看是否开根后还是差1,如果还是差1,那么对区间开根号相当于整个区间减去同一个数,
这样就可以变开根为减了
#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> using namespace std; typedef long long LL; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-‘0‘; return x*f; } ///---------------------------------------------------------------------- const int N=1e5+5; LL sum[N<<2],lz[N<<2],mx[N<<2],mn[N<<2]; void up(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); mn[rt]=min(mn[rt<<1],mn[rt<<1|1]); } void build(int rt,int l,int r) { lz[rt]=0; if(l==r){sum[rt]=read();mn[rt]=mx[rt]=sum[rt];return;} int mid=l+r>>1; build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); up(rt); } void down(int rt,int l,int r) { if(lz[rt]!=0) { int mid=l+r>>1; lz[rt<<1]+=lz[rt]; lz[rt<<1|1]+=lz[rt]; mn[rt<<1]+=lz[rt]; mx[rt<<1]+=lz[rt]; mx[rt<<1|1]+=lz[rt]; mn[rt<<1|1]+=lz[rt]; sum[rt<<1]+=lz[rt]*(mid-l+1); sum[rt<<1|1]+=lz[rt]*(r-mid); lz[rt]=0; } } int x,y,t,T,n,m; void kaigen(int rt,int l,int r) { if(x<=l&&r<=y) { if(mx[rt]==mn[rt]) { lz[rt]-=mx[rt]; mx[rt]=sqrt(mx[rt]); mn[rt]=mx[rt]; lz[rt]+=mx[rt]; sum[rt]=mx[rt]*(r-l+1); return; } else if(mx[rt]==mn[rt]+1) { LL x1=sqrt(mx[rt]); LL x2=sqrt(mn[rt]); if(x1==x2+1) { lz[rt]-=(mx[rt]-x1); sum[rt]-=(mx[rt]-x1)*(r-l+1); mx[rt]=x1;mn[rt]=x2; return; } } } int mid=l+r>>1;down(rt,l,r); if(x<=mid)kaigen(rt<<1,l,mid); if(y>mid)kaigen(rt<<1|1,mid+1,r); up(rt); } void add(int rt,int l,int r) { if(x<=l&&r<=y) { lz[rt]+=t; sum[rt]+=(long long)(r-l+1)*t; mx[rt]+=t;mn[rt]+=t; return ; } int mid=l+r>>1;down(rt,l,r); if(x<=mid)add(rt<<1,l,mid); if(y>mid)add(rt<<1|1,mid+1,r); up(rt); } LL get(int rt,int l,int r) { if(x<=l&&r<=y)return sum[rt]; int mid=l+r>>1;down(rt,l,r); LL ret=0; if(x<=mid)ret+=get(rt<<1,l,mid); if(y>mid)ret+=get(rt<<1|1,mid+1,r); return ret; } int main() { T=read(); while(T--) { n=read();m=read(); build(1,1,n); while(m--) { int op; op=read();x=read();y=read(); if(op==1) { t=read(); add(1,1,n); } else if(op==2)kaigen(1,1,n); else printf("%I64d\n",get(1,1,n)); } } return 0; }