离线+线段树 HDU4228
Posted 不知姓名的黑猫君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了离线+线段树 HDU4228相关的知识,希望对你有一定的参考价值。
题目大意:给一个数组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 + 5; struct point{ LL sum[5]; int cnt; void init(){ this -> cnt = 0; memset(sum, 0, sizeof(sum)); } }tree[maxn << 2]; 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) / 2; if (l <= mid) buildtree(o << 1, l, mid); if (r > mid) buildtree(o << 1 | 1, mid + 1, r); tree[o].init(); } inline void push_up(int o){ tree[o].cnt = tree[o << 1].cnt + tree[o << 1 | 1].cnt; } void display(int o, int l, int r){ printf("o = %d l = %d r = %d\n", o, l, r); for (int i = 0; i < 5; 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[1] += a[pos]; tree[o].cnt = 1;} else {tree[o].sum[1] -= a[pos]; tree[o].cnt = 0;} return ; } int mid = (l + r) / 2; if (pos <= mid) update(o << 1, l, mid, pos, flag); if (pos > mid) update(o << 1 | 1, mid + 1, r, pos, flag); memset(tree[o].sum, 0, sizeof(tree[o].sum)); for (int i = 0; i < 5; i++){ int j = (i + tree[o << 1].cnt) % 5; tree[o].sum[i] += tree[o << 1].sum[i]; tree[o].sum[j] += tree[o << 1 | 1].sum[i]; } ///display(o, l, r); push_up(o); return ; } int main(){ while (scanf("%d", &q) == 1 && q){ int n = 0; for (int i = 1; i <= q; i++){ char s[4]; LL tmp = -1; scanf("%s", s); if (s[0] == ‘d‘ || s[0] == ‘a‘) scanf("%I64d", &tmp); ch[i] = mk(s[0], tmp); if (s[0] == ‘a‘) a[++n] = tmp; } sort(a + 1, a + 1 + n);///有待商榷 buildtree(1, 1, n); for (int i = 1; i <= q; i++){ pair<char, LL> p = ch[i]; if (p.first == ‘s‘){ printf("%I64d\n", tree[1].sum[3]); continue; } else { int pos = lower_bound(a + 1, a + 1 + n, p.second) - a; update(1, 1, n, pos, p.first == ‘a‘); } } } return 0; }
以上是关于离线+线段树 HDU4228的主要内容,如果未能解决你的问题,请参考以下文章
Necklace HDU - 3874 (线段树/树状数组 + 离线处理)
HDU 3333-Turing Tree-线段树+离散+离线