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
两个基本线段树题的融合,成段更新+hdu4027,坑点在于这个开根号到1之后还会有加的操作,如果单纯像4027那样只对一个是否区间都为1剪枝会超时,增加剪枝:
区间内数都为1后,再有操作时区间内数字都相同,
也就是当某区间内值都相同时,各种操作可以只算到这层,然后把lazy标记向下推一层;
参考网上大神完善了代码,比赛时并没能想出来怎么优化TAT。。。好菜啊。。。
ac代码:
#include
using namespace std;
#define rep(i,a,n) for(int i = (a); i < (n); i++)
#define per(i,a,n) for(int i = (n)-1; i >= (a); i--)
#define clr(arr,val) memset(arr, val, sizeof(arr))
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define pi acos(-1)
typedef pair<int, int> pii;
typedef long long LL;
const double eps = 1e-8;
const int mod = 1000000007;
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
const int maxn = 100005;
LL sum[maxn<<2], laz[maxn<<2];
LL mark[maxn<<2];
void PushUp(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
if(mark[rt<<1] == mark[rt<<1|1])
mark[rt] = mark[rt<<1];
else mark[rt] = 0;
return ;
}
void pushdown(int rt, int len){
if(mark[rt]){
mark[rt<<1] = mark[rt<<1|1] = mark[rt];
sum[rt<<1] = mark[rt]*(len-len/2);
sum[rt<<1|1] = mark[rt]*(len/2);
laz[rt] = 0;
}
if(laz[rt]){
laz[rt<<1] += laz[rt];
laz[rt<<1|1] += laz[rt];
sum[rt<<1] += laz[rt]*(len-len/2);
sum[rt<<1|1] += laz[rt]*(len/2);
if(mark[rt<<1]) mark[rt<<1] += laz[rt];
if(mark[rt<<1|1]) mark[rt<<1|1] += laz[rt];
laz[rt] = 0;
}
}
void build(int l, int r, int rt){
laz[rt] = 0;
mark[rt] = 0;
if(l == r){
scanf("%I64d", &sum[rt]);
mark[rt] = sum[rt];
return ;
}
int mid = (l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void add(int L,int R,LL c,int l,int r,int rt){
if(L <= l && R >= r){
sum[rt] += c*(r-l+1);
laz[rt] += c;
if(mark[rt]) mark[rt] += c;
return;
}
pushdown(rt, r-l+1);
int mid = (l+r)>>1;
if(L<=mid)
add(L,R,c,lson);
if(mid < R)
add(L,R,c,rson);
PushUp(rt);
return ;
}
void sq(int L, int R, int l, int r, int rt){
if(L <= l && R >= r && mark[rt]){
mark[rt] = (LL)sqrt(mark[rt]);
sum[rt] = mark[rt]*(r-l+1);
return ;
}
pushdown(rt, r-l+1);
int mid = (l+r)>>1;
if(L <= mid) sq(L, R, lson);
if(mid < R) sq(L, R, rson);
PushUp(rt);
return ;
}
LL query(int L, int R, int l, int r, int rt){
if(L <= l && r <= R){
return sum[rt];
}
pushdown(rt, r-l+1);
int mid = (l+r)>>1;
LL ans = 0;
if(L <= mid) ans += query(L, R, lson);
if(mid < R) ans += query(L, R, rson);
return ans;
}
int main(int argc, char const *argv[]) {
int n, m;
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
build(1, n, 1);
int a, x, y;
LL num;
while(m--){
scanf("%d%d%d", &a, &x, &y);
if(a == 1){
scanf("%I64d", &num);
add(x, y, num, 1, n, 1);
}
if(a == 2)
sq(x, y, 1, n, 1);
if(a == 3)
printf("%I64d\n", query(x, y, 1, n, 1));
}
}
return 0;
}