这道题居然让我想到了 jury_2 的集训队论文,其实确实还是有异曲同工之妙的。
Solution
用线段树维护区间和以及区间最大值。
对于操作
1
,直接
对于操作
2
,假设当前为区间为
对于操作
复杂度为 O((m+n)lognlogw) , w 为权值。
Proof
首先是操作
接着是操作
2
,分析一下取模的性质:
于是对于数
ai
,我们最多将其修改
O(logai)
次,每次修改为
O(logn)
。
由于原数列有
n
个数以及操作
总的来说这还是一道不错的套路题。
#include <cstdio>
#define Max(_A, _B) (_A > _B ? _A : _B)
#define R register
const int MaxN = 100010;
int a[MaxN], B[1 << 18]; long long S[1 << 18];
void Build(R int node, R int begin, R int end)
{
if(begin == end)
{
S[node] = B[node] = a[begin];
return ;
}
R int mid = begin + end >> 1;
Build(node << 1, begin, mid);
Build(node << 1 | 1, mid + 1, end);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
long long Query(R int node, R int begin, R int end, R int l, R int r)
{
if(l <= begin && end <= r) return S[node];
R int mid = begin + end >> 1;
R long long t1 = 0, t2 = 0;
if(l <= mid) t1 = Query(node << 1, begin, mid, l, r);
if(r > mid) t2 = Query(node << 1 | 1, mid + 1, end, l, r);
return t1 + t2;
}
void Updata(R int node, R int begin, R int end, R int pos, R int val)
{
if(begin == end)
{
S[node] = B[node] = val;
return ;
}
R int mid = begin + end >> 1;
if(pos <= mid) Updata(node << 1, begin, mid, pos, val);
else Updata(node << 1 | 1, mid + 1, end, pos, val);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
void Modify(R int node, R int begin, R int end, R int l, R int r, R int val)
{
if(B[node] < val) return ;
if(l <= begin && end <= r)
{
if(begin == end) S[node] = B[node] = S[node] % val;
else
{
R int mid = begin + end >> 1;
if(B[node << 1] >= val) Modify(node << 1, begin, mid, l, r, val);
if(B[node << 1 | 1] >= val) Modify(node << 1 | 1, mid + 1, end, l, r, val);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
return ;
}
R int mid = begin + end >> 1;
if(l <= mid) Modify(node << 1, begin, mid, l, r, val);
if(r > mid) Modify(node << 1 | 1, mid + 1, end, l, r, val);
S[node] = S[node << 1] + S[node << 1 | 1];
B[node] = Max(B[node << 1], B[node << 1 | 1]);
}
int main()
{
R int n, m;
scanf("%d %d", &n, &m);
for(R int i = 1; i <= n; i++) scanf("%d", &a[i]);
Build(1, 1, n);
while(m--)
{
R int opt;
scanf("%d", &opt);
if(opt == 1)
{
R int l, r;
scanf("%d %d", &l, &r);
printf("%lld\n", Query(1, 1, n, l, r));
}
if(opt == 2)
{
R int l, r, x;
scanf("%d %d %d", &l, &r, &x);
Modify(1, 1, n, l, r, x);
}
if(opt == 3)
{
R int k, x;
scanf("%d %d", &k, &x);
Updata(1, 1, n, k, x);
}
}
return 0;
}