CF558E A Simple Task

Solution

和之前有道省选题很像,同样是用线段树来实现排序操作。但这道题不同之处在于值域很小,以致于每个数的个数可以直接分别用线段树统计出来,这正是这道题的突破口。后面的就很好想了,每次对一个区间排序只需要统计所有字母的出现次数,然后按顺序区间覆盖,易知复杂度是 \(O(n\log{n})\) 的,带一个 26 的大常数(显然跑不满)。

#include<stdio.h>
#include<string.h>
#define N 100007
#define lid id<<1
#define rid id<<1|1

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

struct Node{
    int s[30],cov,l,r,mid;
}t[N<<2];

char s[N];
int n,m;

void merge(Node &id,Node x,Node y){
    for(int i=1;i<=26;i++)
        id.s[i]=x.s[i]+y.s[i];
}

void build(int id,int lf,int rf){
    t[id].l=lf,t[id].r=rf;
    if(lf==rf) t[id].s[s[lf]-'a'+1]=1;
    else{
        t[id].mid=(lf+rf)>>1;
        build(lid,lf,t[id].mid);
        build(rid,t[id].mid+1,rf);
        merge(t[id],t[lid],t[rid]);
    }
}

void push(int id,int val){
    t[id].cov=val;
    for(int i=1;i<=26;i++) t[id].s[i]=0;
    t[id].s[val]=t[id].r-t[id].l+1;
}

void pushdown(int id){
    push(lid,t[id].cov);
    push(rid,t[id].cov);
    t[id].cov=0;
}

int l,r,val;
Node query(int id){
    if(l<=t[id].l&&t[id].r<=r) return t[id];
    if(t[id].cov) pushdown(id);
    if(r<=t[id].mid) return query(lid);
    else if(l>t[id].mid) return query(rid);
    Node tmp;
    merge(tmp,query(lid),query(rid));
    return tmp;
}

void modify(int id){
    if(l<=t[id].l&&t[id].r<=r) push(id,val);
    else{
        if(t[id].cov) pushdown(id);
        if(l<=t[id].mid) modify(lid);
        if(r>t[id].mid) modify(rid);
        merge(t[id],t[lid],t[rid]);
    }
}

void print(){
    for(int i=1;i<=n;i++){
        l=r=i;
        Node ret=query(1);
        for(int i=1;i<=26;i++)
            if(ret.s[i]) putchar('a'+i-1);
    }
//    putchar('\n');
}

int main(){
    n=read(),m=read();
    scanf("%s",s+1);
    build(1,1,n);
    int op;
    for(int i=1;i<=m;i++){
        l=read(),r=read(),op=read();
        Node ret=query(1);
        if(op){
            int l_,r_=l-1;
            for(int i=1;i<=26;i++){
                if(!ret.s[i]) continue;
                l=r_+1,r=r_+ret.s[i],val=i,modify(1);
                r_=r;
            }
        }else{
            int l_,r_=l-1;
            for(int i=26;i;i--){
                if(!ret.s[i]) continue;
                l=r_+1,r=r_+ret.s[i],val=i,modify(1);
                r_=r;
            }
        }
    //    print();
    }
    print();
}
posted @ 2020-12-25 20:39  Kreap  阅读(72)  评论(0编辑  收藏  举报