求余区间的求和类问题 离线+线段树 HDU4228

时间:2022-09-02 23:48:13

题目大意:给一个数组a,他的顺序是严格的单调增,然后有如下三个操作

①加入一个val到a数组里面去,加入的位置就是a[i-1]<val<a[i+1]

②删除一个a[i]=val的值

③查询所有下标i%5=3的值

思路:线段树+离线

首先因为线段树中不支持添加、删除操作的,所以只能离线把所有的val离散化以后放到区间里面去。然后关键就是线段树是怎么建立的。

我们知道,每个%5都会有0,1,2,3,4这5个值,然后我们可以通过线段树来维护这5个值。我们首先用sum[5]表示能被5整除的5种求余后不同类型的数的val,然后再用cnt记录当前这个区间里面还存在的数值。接下来我们定义父亲区间,左子区间和右子区间,然后我们发现左子区间的区间范围和父亲区间的是一样的,然后右子区间的范围要发生改变,他的位置改变到如下位置:(i+cnt)%5,其中i表示右子区间的第几个区间,然后cnt表示左子区间的有效的个数。然后我们就这样去维护就好啦。

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
const int maxn = 1e5 + ;
struct point{
LL sum[];
int cnt;
void init(){
this -> cnt = ;
memset(sum, , sizeof(sum));
}
}tree[maxn << ];
LL a[maxn];
int q;
pair<char, LL> ch[maxn]; void buildtree(int o, int l, int r){
if (l == r){
tree[o].init();
return ;
}
int mid = (l + r) / ;
if (l <= mid) buildtree(o << , l, mid);
if (r > mid) buildtree(o << | , mid + , r);
tree[o].init();
} inline void push_up(int o){
tree[o].cnt = tree[o << ].cnt + tree[o << | ].cnt;
} void display(int o, int l, int r){
printf("o = %d l = %d r = %d\n", o, l, r);
for (int i = ; i < ; i++) printf("%d ", tree[o].sum[i]);
printf("\n");
} void update(int o, int l, int r, int pos, bool flag){
if (l == r && l == pos){
if (flag) {tree[o].sum[] += a[pos]; tree[o].cnt = ;}
else {tree[o].sum[] -= a[pos]; tree[o].cnt = ;}
return ;
}
int mid = (l + r) / ;
if (pos <= mid) update(o << , l, mid, pos, flag);
if (pos > mid) update(o << | , mid + , r, pos, flag);
memset(tree[o].sum, , sizeof(tree[o].sum));
for (int i = ; i < ; i++){
int j = (i + tree[o << ].cnt) % ;
tree[o].sum[i] += tree[o << ].sum[i];
tree[o].sum[j] += tree[o << | ].sum[i];
}
///display(o, l, r);
push_up(o);
return ;
} int main(){
while (scanf("%d", &q) == && q){
int n = ;
for (int i = ; i <= q; i++){
char s[]; LL tmp = -;
scanf("%s", s);
if (s[] == 'd' || s[] == 'a') scanf("%I64d", &tmp);
ch[i] = mk(s[], tmp);
if (s[] == 'a') a[++n] = tmp;
}
sort(a + , a + + n);///有待商榷
buildtree(, , n);
for (int i = ; i <= q; i++){
pair<char, LL> p = ch[i];
if (p.first == 's'){
printf("%I64d\n", tree[].sum[]);
continue;
}
else {
int pos = lower_bound(a + , a + + n, p.second) - a;
update(, , n, pos, p.first == 'a');
}
}
}
return ;
}