codeforces 899 F - Letters Removing (线段树)

题意:给你一个长度为n的字符串,只包括大小写字母与数字,还有q个操作,对于每个操作 将[l,r]区间内删除字符ch


题解:对于这个操作l,r,是之间操作完的串的l,r,也就是你还需要找到原始串中的l,r
方法是开62个线段树,每一个维护区间和,那么对于如何寻找原来的l,r,进行前缀和的二分查找,前缀和等于l的地方就是原始串中l的地方


这题把我折磨死了= =。 62个线段树刚好卡在内存附近,打的lazy标记需要改成flag,反正是区间修改1和0


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 5;
typedef long long LL;
char s[maxn];
int sum[maxn * 4][65];
bool lazy[maxn * 4][65];
int getid(char x){
    if('a' <= x && x <= 'z') return (int)(x - 'a');
    else if('A' <= x && x <= 'Z') return (int)(x - 'A' + 26);
    return (int)(x - '0' + 52);
}
void bulid(int l, int r, int o){
    if(l == r){
        sum[o][getid(s[l])] = 1;
        return;
    }
    int m = (l + r) / 2;
    bulid(l, m, o*2);
    bulid(m+1, r, o*2+1);
    for(int i=0; i<62; i++){
        sum[o][i] = sum[o*2][i] + sum[o*2+1][i];
    }
}
void pushdown(int o, int pos){
    if(lazy[o][pos]){
        sum[o*2][pos] = 0;
        sum[o*2+1][pos] = 0;
        lazy[o*2][pos] = lazy[o*2+1][pos] = lazy[o][pos];
        lazy[o][pos] = false;
    }
}
void update(int l, int r, int ql, int qr, int o, int k){
    if(ql <= l && qr >= r){
        sum[o][k] = 0;
        lazy[o][k] = true;
        return;
    }
    int m = (l + r) / 2;
    for(int i=0; i<62; i++)
        pushdown(o,i);
    if(m >= ql)
        update(l,m,ql,qr,o*2,k);
    if(m < qr)
        update(m+1,r,ql,qr,o*2+1,k);
    for(int i=0; i<62; i++)
        sum[o][i] = sum[o*2][i] + sum[o*2+1][i];
}
void print(int l, int r, int o){
    if(l == r){
        for(int i=0; i<62; i++)
            if(sum[o][i] > 0){
                printf("%c",s[l]);
                break;
            }
        return;
    }
    int m = (l + r) / 2;
    for(int i=0; i<62; i++)
        pushdown(o,i);
    print(l,m,o*2);
    print(m+1,r,o*2+1);
}
int FIND(int l, int r, int o, int k){
    if(l == r){
        return l;
    }
    for(int i=0; i<62; i++)
        pushdown(o, i);
    int m = (l + r) / 2;
    int ans = 0;
    for(int i=0; i<62; i++){
        ans += sum[o*2][i];
    }
    if(ans >= k) return FIND(l,m,o*2,k);
    else
        return FIND(m+1,r,o*2+1,k - ans);
}
int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    scanf("%s",s+1);
    bulid(1,n,1);
    while(q--){
        int l, r;
        char ch;
        scanf("%d%d %c",&l,&r,&ch);
        l = FIND(1,n,1,l);
        r = FIND(1,n,1,r);
        update(1,n,l,r,1,getid(ch));
    }
    print(1,n,1);
    printf("\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值