首页 > 代码库 > 好题 线段树对数据的保存+离线的逆向插入 POJ 2887

好题 线段树对数据的保存+离线的逆向插入 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 secondconst 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;}
View Code

 

好题 线段树对数据的保存+离线的逆向插入 POJ 2887