您的位置:首页 > 运维架构

日常训练 维护序列(包含区间除)

2017-03-29 18:45 495 查看
题意简述:修改:1 l r c:区间l∼r每个元素加上c,2 l r c:区间l∼r每个元素除以d下取整,3 l r,求l∼r的最小值,4 l r,求l∼r的区间和。序列长度n,操作数q满足n,q≤105。

除法会使区间内元素越除差别越小,当一个区间最大值和最小值因为除法而减去的数相同时可以作为一个区间减法打成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
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树
相关文章推荐