题意:给定只含小写字母、大写字母和数字的字符串,每次给定一个范围要求删除[l,r]内的字符c(l和r具体位置随删除变动),求m次操作后的字符串。n<=2*10^5。

思路:这里l和r的位置会随删除变动,所以要先知道l和r的原本位置,这里可以将序列中存在记为1,删除记为0,转化为找前缀和恰好为l和r的位置,就是原本的位置了,可以维护每个区间剩余字符的个数num和区间中每个字符的个数sum,通过num来求出每个l,r对应的在线段树上的l,r。 这里涉及到线段树上的前缀和的位置的求法,然后区间更新即可。

int find(int id,int x)//二分查找前缀和
{
    int l=node[id].left;
    int r=node[id].right;
    if(l==r)return l;
    if(x<=node[id<<1].num)return find(id<<1,x);
    else return find(id<<1|1,x-node[id<<1].num);
}

代码

int n;
char a[200010];
struct Node
{
    int left,right;
    int sum[65];
    int num;//区间有多少个没被删除的数字 0:被删除 1:没被删除
}node[200010<<2];
int ans;
int trans(char x)
{
    if(x>='A'&&x<='Z')return x-'A';
    if(x>='a'&&x<='z')return x-'a'+26;
    return x-'0'+52;
}
void build(int l,int r,int id)//建树
{
    node[id].left=l;
    node[id].right=r;
    if(l==r)
    {
        node[id].sum[trans(a[l])]=1;
        node[id].num=1;
        return;
    }
    int m=(l+r)>>1;
    build(l,m,id<<1);
    build(m+1,r,id<<1|1);
    node[id].num=node[id<<1].num+node[id<<1|1].num;
    for(int i=0;i<62;i++)
       node[id].sum[i]=node[id<<1].sum[i]+node[id<<1|1].sum[i];
}
int find(int id,int x)//二分查找前缀和
{
    int l=node[id].left;
    int r=node[id].right;
    if(l==r)return l;
    if(x<=node[id<<1].num)return find(id<<1,x);
    else return find(id<<1|1,x-node[id<<1].num);
}
void update(int L,int R,int c,int id)
{
    if(node[id].sum[c]==0)return;
    int l=node[id].left;
    int r=node[id].right;
    if(l==r)
    {
        node[id].num=0;
        node[id].sum[c]=0;
        return;
    }
    int m=(l+r)/2;
    if(L<=m)update(L,R,c,id<<1);
    if(R>m)update(L,R,c,(id<<1|1));
    node[id].num=node[id<<1].num+node[id<<1|1].num;
    node[id].sum[c]=node[id<<1].sum[c]+node[id<<1|1].sum[c];
}
void output(int id)
{
    int l=node[id].left;
    int r=node[id].right;
    if(l==r)
    {
        //printf("%d:%d\n",id,node[id].num);
        if(node[id].num==1)
            printf("%c",a[l]);
        return;
    }
    output(id<<1);
    output(id<<1|1);
}
int main()
{
    int m;
    scanf("%d%d",&n,&m);
    scanf("%s",a+1);
    build(1,n,1);
    int l,r;
    char c;
    while(m--)
    {
        scanf("%d%d %c",&l,&r,&c);
        l=find(1,l);
        r=find(1,r);
        update(l,r,trans(c),1);
    }
    output(1);
    printf("\n");
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

树状数组 Previous
CodeForces899E 模拟链表+优先队列+pair Next