题意简述:修改:
1 l r c
:区间
l∼r
每个元素加上
c
,
除法会使区间内元素越除差别越小,当一个区间最大值和最小值因为除法而减去的数相同时可以作为一个区间减法打成tag。(具体证明不是很会)
#include<bits/stdc++.h>
typedef long long ll;
const int N = 1e5 + 50;
struct rec{
int l,r,min,max,flag;
long long sum;
};
rec tr[N * 8];
int a[N];
template <typename T> void read(T &x){
x = 0;int f = 1;
char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f *= -1; c = getchar();}
while (c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();}
x *= f;
}
void updata(int i){
tr[i].min = std::min(tr[i * 2].min,tr[i * 2 + 1].min);
tr[i].max = std::max(tr[i * 2].max,tr[i * 2 + 1].max);
tr[i].sum = tr[i * 2].sum+tr[i * 2 + 1].sum;
return;
}
void build(int i, int l, int r){
tr[i].l = l; tr[i].r = r; tr[i].flag = 0;
if (l == r) {tr[i].sum = tr[i].min = tr[i].max = a[l]; return;}
int mid = (l + r) >> 1;
build(i * 2, l, mid);
build(i * 2 + 1, mid + 1, r);
updata(i);
//printf("i=%d l=%d r=%d min=%d max=%d sum=%lld\n",i,l,r,tr[i].min,tr[i].max,tr[i].sum);
return;
}
void push(int i){
if (tr[i].flag == 0) return;
tr[i * 2].min += tr[i].flag;
tr[i * 2 + 1].min += tr[i].flag;
tr[i * 2].max += tr[i].flag;
tr[i * 2 + 1].max += tr[i].flag;
tr[i * 2].flag += tr[i].flag;
tr[i * 2 + 1].flag += tr[i].flag;
tr[i * 2].sum += (ll)tr[i].flag * (tr[i * 2].r - tr[i * 2].l + 1);
tr[i * 2 + 1].sum += (ll)tr[i].flag * (tr[i * 2 + 1].r - tr[i * 2 + 1].l + 1);
tr[i].flag = 0;
return;
}
void add(int i, int l, int r, int c){
push(i);
if (tr[i].l == l && tr[i].r == r){
tr[i].flag += c;
tr[i].min += c;
tr[i].max += c;
tr[i].sum += (ll)c * (tr[i].r - tr[i].l + 1);
return;
}
int mid = (tr[i].l + tr[i].r) >> 1;
if (r <= mid)
add(i * 2, l, r, c);
else if (l > mid)
add(i * 2 + 1, l, r, c);
else{
add(i * 2, l, mid, c);
add(i * 2 + 1, mid + 1, r, c);
}
updata(i);
return;
}
int d(int x, int y){
int z = x / y;
if (z * y > x)
return z - 1;
else
return z;
if (x < 0)
return (x - y + 1) / y;
else
return x / y;
}
void div(int i, int l, int r, int c){
push(i);
if (tr[i].l == l && tr[i].r == r && tr[i].min - d(tr[i].min, c) == tr[i].max - d(tr[i].max, c)){
int det = tr[i].min - d(tr[i].min, c);
tr[i].min -= det;
tr[i].max -= det;
tr[i].flag -= det;
tr[i].sum -= (ll)det * (tr[i].r - tr[i].l + 1);
return;
}
int mid = (tr[i].l + tr[i].r) >> 1;
if (r <= mid)
div(i * 2, l, r, c);
else if (l > mid)
div(i * 2 + 1, l, r, c);
else{
div(i * 2, l, mid, c);
div(i * 2 + 1, mid + 1, r, c);
}
updata(i);
return;
}
int query_min(int i, int l, int r){
push(i);
if (tr[i].l == l && tr[i].r == r)
return tr[i].min;
int mid = (tr[i].l + tr[i].r) >> 1;
if (r <= mid) return query_min(i * 2, l, r);
if (l > mid) return query_min(i * 2 + 1, l, r);
return std::min(query_min(i * 2, l, mid),query_min(i * 2 + 1, mid + 1, r));
}
long long query_sum(int i, int l, int r){
push(i);
if (tr[i].l == l && tr[i].r == r)
return tr[i].sum;
int mid = (tr[i].l + tr[i].r) >> 1;
if (r <= mid) return query_sum(i * 2, l, r);
if (l > mid) return query_sum(i * 2 + 1, l, r);
return query_sum(i * 2, l, mid) + query_sum(i * 2 + 1, mid + 1, r);
}
void print_tree(){
for (int i=1; i<=9; i++)
printf("i=%d l=%d r=%d min=%d max=%d flag=%d sum=%lld\n",
i,tr[i].l,tr[i].r,tr[i].min,tr[i].max,tr[i].flag,tr[i].sum);
printf("\n");
return;
}
int main(){
freopen("market.in","r",stdin);
freopen("market.out","w",stdout);
int n,q;
read(n);read(q);
for (int i=1; i<=n; i++)
read(a[i]);
build(1,1,n);
print_tree();
int type,l,r,c;
for (; q>0; q--){
read(type);
if (type < 3){
read(l);read(r);read(c);
l++;r++;
if (type == 1)
add(1,l,r,c);
else
div(1,l,r,c);
}else{
read(l);read(r);
l++;r++;
if (type == 3)
printf("%d\n",query_min(1,l,r));
else
printf("%lld\n",query_sum(1,l,r));
}
print_tree();
}
return 0;
}