http://codeforces.com/problemset/problem/438/D
At the children's day, the child came to Picks's house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks.
Fortunately, Picks remembers how to repair the sequence. Initially he should create an integer array a[1], a[2], ..., a[n]. Then he should perform a sequence of m operations. An operation can be one of the following:
- Print operation l, r. Picks should write down the value of .
- Modulo operation l, r, x. Picks should perform assignment a[i] = a[i] mod x for each i (l ≤ i ≤ r).
- Set operation k, x. Picks should set the value of a[k] to x (in other words perform an assignment a[k] = x).
Can you help Picks to perform the whole sequence of operations?
Input
The first line of input contains two integer: n, m (1 ≤ n, m ≤ 105). The second line contains n integers, separated by space: a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ 109) — initial value of array elements.
Each of the next m lines begins with a number type .
- If type = 1, there will be two integers more in the line: l, r (1 ≤ l ≤ r ≤ n), which correspond the operation 1.
- If type = 2, there will be three integers more in the line: l, r, x (1 ≤ l ≤ r ≤ n; 1 ≤ x ≤ 109), which correspond the operation 2.
- If type = 3, there will be two integers more in the line: k, x (1 ≤ k ≤ n; 1 ≤ x ≤ 109), which correspond the operation 3.
Output
For each operation 1, please print a line containing the answer. Notice that the answer may exceed the 32-bit integer.
Examples
Input
5 5 1 2 3 4 5 2 3 5 4 3 3 5 1 2 5 2 1 3 3 1 1 3
Output
8 5
Input
10 10 6 9 6 7 6 1 10 10 9 5 1 3 9 2 7 10 9 2 5 10 8 1 4 7 3 3 7 2 7 9 9 1 2 4 1 6 6 1 5 9 3 1 10
Output
49 15 23 1 9
Note
Consider the first testcase:
- At first, a = {1, 2, 3, 4, 5}.
- After operation 1, a = {1, 2, 3, 0, 1}.
- After operation 2, a = {1, 2, 5, 0, 1}.
- At operation 3, 2 + 5 + 0 + 1 = 8.
- After operation 4, a = {1, 2, 2, 0, 1}.
- At operation 5, 1 + 2 + 2 = 5.
题目大意:给n个数,三种操作:查询区间和,区间取模,单点修改。
思路:对于一段区间,如果取模的数比这段区间所有的数都大,那取模就是没有意义的,就是说,如果取模的数比区间最大的数还大,那么就不用取模了,所以我们在线段树里再记录一个区间最大值。考虑每次取模,对于每一个数x,取模y,x mod y的值必然比y小,如果y小于x/2,那x就变得小于x/2,如果y大于x/2,x剩下的部分也比x/2少,x也会变得比x/2小。那么就是说x每次取模都会变得比x/2小,就是说,对于一个数x,有效的取mod最多进行logx次,一共只会进行nlogn次取模,那么就算对所有的数取模,这个时间复杂度都是可以接受的。那么我们对于每个区间记录一个最大值,如果取模的数大于最大值,就不管,如果小于最大值,就暴力取模。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxl=1e5;
struct node
{
int l,r;
int maxn;
ll sum;
};
node tree[maxl*4+5];
int a[maxl];
int n,m;
void build(int i,int l,int r)//i为当前节点编号 区间为[l,r]
{
tree[i].l=l,tree[i].r=r;
if(l==r)//叶子节点
{
tree[i].maxn=a[l];
tree[i].sum=a[l];
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);//左子树
build(i<<1|1,mid+1,r);//右子树
tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);//维护
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}
void update(int i,int p,int c)//i为当前节点编号 把[p,p]节点的值改为c
{
if(tree[i].l==tree[i].r&&tree[i].r==p)//叶子节点
{
tree[i].maxn=c;
tree[i].sum=c;
return ;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(p<=mid)//左半区间
update(i<<1,p,c);
else //右半区间
update(i<<1|1,p,c);
tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}
void updatemod(int i,int x,int y,int v)//区间取模
{
if(v>tree[i].maxn)
return ;
if(tree[i].l==tree[i].r)
{
tree[i].maxn%=v;
tree[i].sum=tree[i].maxn;
return ;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(y<=mid)
updatemod(i<<1,x,y,v);
else if(x>mid)
updatemod(i<<1|1,x,y,v);
else
updatemod(i<<1,x,mid,v),
updatemod(i<<1|1,mid+1,y,v);
tree[i].maxn=max(tree[i<<1].maxn,tree[i<<1|1].maxn);
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}
ll query(int i,int l,int r)
{
if(tree[i].l==l&&tree[i].r==r)//当前区间刚好是要找的区间
return tree[i].sum;
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)//要查询的区间在左半部分
return query(i<<1,l,r);
else if(l>=mid+1)//要查询的区间在右半部分
return query(i<<1|1,l,r);
else //左右两边均有
return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
int op,l,r,x;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&op,&l,&r);
if(op==1)
printf("%lld\n",query(1,l,r));
else if(op==2)
{
scanf("%d",&x);
updatemod(1,l,r,x);
}
else
update(1,l,r);
}
return 0;
}