好题 线段树对数据的保存+离线的逆向插入 POJ 2887
Posted 不知姓名的黑猫君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了好题 线段树对数据的保存+离线的逆向插入 POJ 2887相关的知识,希望对你有一定的参考价值。
题目大意:给一个字符串,有插入和询问操作,每次往一个位置插入一个字符或者询问第p个位置的字符是什么。
思路:我们离线询问,逆向把所有的字符都插入给线段树,然后再查询就好了,每次都要记得插入线段树的最后的位置,然后要把这个位置给保存下来在O(1)查询即可。
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <cstdio> #include<cstring> #include<algorithm> #include<cmath> 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 maxq = 2000 + 5; const int maxch = 1002000 + 5; int tree[maxch << 2]; inline void pushup(int o){ tree[o] = tree[o << 1] + tree[o << 1 | 1]; } void buildtree(int o, int l, int r){ if (l == r){ tree[o] = 1; return ; } int mid = (l + r) / 2; if (l <= mid) buildtree(o << 1, l ,mid); if (r > mid) buildtree(o << 1 | 1, mid + 1, r); pushup(o); } void update(int o, int l, int r, int pos, int val){ if (l == r && l == pos){ tree[o] = val; return ; } int mid = (l + r) / 2; if (pos <= mid) update(o << 1, l, mid, pos, val); if (pos > mid) update(o << 1 | 1, mid + 1, r, pos, val); pushup(o); } int query(int o, int l, int r, int pos){ if (l == r) return l; int mid = (l + r) / 2; if (tree[o << 1] >= pos) return query(o << 1, l, mid, pos); if (tree[o << 1] < pos) return query(o << 1 | 1, mid + 1, r, pos - tree[o << 1]); } ///要知道的东西:询问,初始的ch,线段树节点上的val,线段树该节点下还有多少子节点 struct Query{ int ty, pos, cnt;///表示目前有几个插入的 char val; Query(int ty = 0, char val = 0, int pos = 0, int cnt = 0): ty(ty), val(val), pos(pos), cnt(cnt){} }q[maxch]; int tpos[maxch], Q; char tval[maxch], ch[maxch]; int main(){ scanf("%s", ch); int len = strlen(ch); scanf("%d", &Q); int cnt = len; for (int i = 1; i <= Q; i++){ char c[2]; scanf("%s", c); if (c[0] == ‘I‘) { char cc[2]; scanf("%s", cc); int pos; scanf("%d", &pos); q[i] = Query(c[0], cc[0], pos, cnt + 1);///目前该询问下的种类,val和位置,加上已经有了多少个字母了 cnt++; } else { int pos; scanf("%d", &pos); q[i] = Query(c[0], 0, pos, cnt); } } /*①逆序放入②得到逆序放入以后放入位置的val是多少*/ int n = cnt; ///printf("n = %d\n", n); buildtree(1, 1, n); for (int i = Q; i >= 1; i--){///知道他是在哪个位置的 if (q[i].ty == ‘I‘){ q[i].pos = min(q[i].pos, q[i].cnt); int p = query(1, 1, n, q[i].pos); ///线段树里面的位置 tpos[i] = p; tval[p] = q[i].val;///线段树该位置下的val update(1, 1, n, p, 0); } } for (int i = 1, j = 0; i <= n; i++){ if (tval[i] == 0){ tval[i] = ch[j]; j++; } } for (int i = 1; i <= Q; i++){ if (q[i].ty == ‘I‘){ update(1, 1, n, tpos[i], 1); } else { int p = query(1, 1, n, q[i].pos); printf("%c\n", tval[p]); } } return 0; }
以上是关于好题 线段树对数据的保存+离线的逆向插入 POJ 2887的主要内容,如果未能解决你的问题,请参考以下文章
POJ 1804 Brainman(5种解法,好题,暴力,归并排序,线段树单点更新,树状数组,平衡树)