POJ 2887 Big String 线段树离线

本文介绍了一种使用线段树数据结构来高效处理字符串插入和查询操作的方法。面对给定的字符串及其两种操作——在指定位置插入字符和查询指定位置的字符——文章详细解释了如何构建和维护线段树,确保所有操作能在较短时间内完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

http://poj.org/problem?id=2887

题意:

初始给定一个字符串,然后有两种操作: I ch p 在第 p 个字符前插入字符ch Q p 查询第 p 个位置上的字符。下标均是从1开始

思路:

线段树离线操作,脑洞大开

#include <bits/stdc++.h>

using namespace std;

const int N = 1000000 + 10, INF = 0x3f3f3f3f;

char ori[N], pat[N];
char op[N], ch[N];
int num[N], pos[N], rpos[N];

struct node
{
    int l, r, val;
}tr[N*4];
void push_up(int k)
{
    tr[k].val = tr[k<<1].val + tr[k<<1|1].val;
}
void build(int l, int r, int k)
{
    tr[k].l = l, tr[k].r = r, tr[k].val = 0;
    if(l == r)
    {
        tr[k].val = 1; return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, k << 1);
    build(mid + 1, r, k << 1|1);
    push_up(k);
}
void update(int x, int val, int k)
{
    if(tr[k].l == tr[k].r)
    {
        tr[k].val = val; return;
    }
    int mid = (tr[k].l + tr[k].r) >> 1;
    if(x <= mid) update(x, val, k << 1);
    else update(x, val, k << 1|1);
    push_up(k);
}
int query(int x, int k)
{
    if(tr[k].l == tr[k].r) return tr[k].l;
    if(x <= tr[k<<1].val) return query(x, k << 1);
    else return query(x - tr[k<<1].val, k << 1|1);
}
int main()
{
    int m;
    scanf("%s", ori);
    int len = strlen(ori);
    scanf("%d", &m);
    num[0] = len;
    for(int i = 1; i <= m; i++)
    {
        scanf(" %c", &op[i]);
        if(op[i] == 'I')
        {
            scanf(" %c%d", &ch[i], &pos[i]);
            num[i] = num[i-1] + 1;
        }
        else scanf("%d", &pos[i]), num[i] = num[i-1];
    }
    int n = num[m];
    build(1, n, 1);
    for(int i = m; i >= 1; i--) //从后往前开始插入到线段树,从前往后的话,后插入的状态影响之前的状态,造成位置无法确定
        if(op[i] == 'I')
        {
            pos[i] = min(pos[i], num[i]);
            rpos[i] = query(pos[i], 1);//真正要插入的位置
            update(rpos[i], 0, 1); //消除当前状态对之后插入状态的影响
            pat[rpos[i]] = ch[i];
        }
    int idx = 0;
    for(int i = 1; i <= n; i++) //把原串补进去
        if(pat[i] == '\0') pat[i] = ori[idx++];
    for(int i = 1; i <= m; i++)
    {
        if(op[i] == 'Q')
        {
            int ans = query(pos[i], 1);//查询位置
            printf("%c\n", pat[ans]);
        }
        else update(rpos[i], 1, 1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值