Rikka with Sequence
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 631 Accepted Submission(s): 183
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
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?
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
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.
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
Recommend
题意:给你n个数,序列为1~n,三种操作,1是l~r之间的数全部加x,2是l~r之间的数全部开方,3求l~r之间的数的和。
思路:很明显这道题要用线段树,关键是怎么优化,操作1的优化估计大家都会,问题是操作2,第一种情况,一个数连续开方不超10次就会变成1,而1开方也还是1,那么我们只要判断区间里的数全部都是1就不用继续更新下去了,第二种情况,区间里的数全部相等,也就是区间的最大值等于最小值,那么开方之后的结果很容易就得出来了。下面给代码。
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 100005
#define ll now<<1
#define rr now<<1|1
typedef long long LL;
LL sum[maxn << 2], minnum[maxn << 2], maxnum[maxn << 2], value[maxn << 2], addnum;
void build(int l, int r, int now){
if (l == r){
scanf("%lld", &sum[now]);
maxnum[now] = minnum[now] = sum[now];
return;
}
int mid = (l + r) >> 1;
build(l, mid, ll);
build(mid + 1, r, rr);
sum[now] = sum[ll] + sum[rr];
minnum[now] = min(minnum[ll], minnum[rr]);
maxnum[now] = max(maxnum[ll], maxnum[rr]);
value[now] = 0;
}
void updateadd(int l1, int r1, int l2, int r2, int now){
if (l2 <= l1&&r2 >= r1){
sum[now] += addnum*(r1 - l1 + 1);
maxnum[now] += addnum;
minnum[now] += addnum;
value[now] += addnum;
return;
}
int mid = (l1 + r1) >> 1;
if (value[now]){
sum[ll] += (mid - l1 + 1)*value[now];
sum[rr] += (r1 - mid)*value[now];
maxnum[ll] += value[now];
maxnum[rr] += value[now];
minnum[ll] += value[now];
minnum[rr] += value[now];
value[ll] += value[now];
value[rr] += value[now];
value[now] = 0;
}
if (l2 <= mid)
updateadd(l1, mid, l2, r2, ll);
if (r2 > mid)
updateadd(mid + 1, r1, l2, r2, rr);
sum[now] = sum[ll] + sum[rr];
maxnum[now] = max(maxnum[ll], maxnum[rr]);
minnum[now] = min(minnum[ll], minnum[rr]);
}
void updatesqrt(int l1, int r1, int l2, int r2, int now){
if (maxnum[now] == 1){
return;
}
if (l2 <= l1&&r2 >= r1&&minnum[now] == maxnum[now]){
LL temp = sqrt(maxnum[now]);
sum[now] = (r1 - l1 + 1)*temp;
value[now] -= maxnum[now] - temp;
maxnum[now] = temp;
minnum[now] = temp;
return;
}
int mid = (l1 + r1) >> 1;
if (value[now]){
sum[ll] += (mid - l1 + 1)*value[now];
sum[rr] += (r1 - mid)*value[now];
maxnum[ll] += value[now];
maxnum[rr] += value[now];
minnum[ll] += value[now];
minnum[rr] += value[now];
value[ll] += value[now];
value[rr] += value[now];
value[now] = 0;
}
if (l2 <= mid)
updatesqrt(l1, mid, l2, r2, ll);
if (r2 > mid)
updatesqrt(mid + 1, r1, l2, r2, rr);
sum[now] = sum[ll] + sum[rr];
maxnum[now] = max(maxnum[ll], maxnum[rr]);
minnum[now] = min(minnum[ll], minnum[rr]);
}
LL query(int l1, int r1, int l2, int r2, int now){
if (l2 <= l1&&r2 >= r1){
return sum[now];
}
int mid = (l1 + r1) >> 1;
if (value[now]){
sum[ll] += (mid - l1 + 1)*value[now];
sum[rr] += (r1 - mid)*value[now];
maxnum[ll] += value[now];
maxnum[rr] += value[now];
minnum[ll] += value[now];
minnum[rr] += value[now];
value[ll] += value[now];
value[rr] += value[now];
value[now] = 0;
}
LL lsum = 0, rsum = 0;
if (l2 <= mid)
lsum = query(l1, mid, l2, r2, ll);
if (r2 > mid)
rsum = query(mid + 1, r1, l2, r2, rr);
return lsum + rsum;
}
int main(){
int t;
scanf("%d", &t);
while (t--){
int n, m;
scanf("%d%d", &n, &m);
build(1, n, 1);
while (m--){
int cmd, l, r;
scanf("%d%d%d", &cmd, &l, &r);
if (cmd == 1){
scanf("%lld", &addnum);
updateadd(1, n, l, r, 1);
}
else if (cmd == 2){
updatesqrt(1, n, l, r, 1);
}
else{
printf("%lld\n", query(1, n, l, r, 1));
}
}
}
}