题意:

给定一个长度不超过10^5的字符串和不超过m次操作。
每个操作 L R K 表示给区间[L,R]的字符串排序,K=1为升序,K=0为降序。
最后输出最终的字符串。

做法:线段树

思路:

  • 根据计数排序的原理,只要知道了有几个数比t小,就可以知道t的位置

  • 这道题只有26个字母,我们只需建26颗线段树

  • 在每次操作时,首先求出这个区间中a~z每个数出现的次数

  • 再分别对每一位字母进行区间覆盖。

  • 对下一个区间进行覆盖要加上之前覆盖的长度

  • 如果是升序排序,我们从a到z依次查询所有线段树,降序就从z到a依次查询

  • 最后遍历整棵线段树输出最终的字符串

代码

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp(aa,bb) make_pair(aa,bb)
#define _for(i,b) for(int i=(0);i<(b);i++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,b,a) for(int i=(b);i>=(a);i--)
#define mst(abc,bca) memset(abc,bca,sizeof abc)
#define X first
#define Y second
#define lowbit(a) (a&(-a))
#define debug(a) cout<<#a<<":"<<a<<"\n"
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long double ld;
const int N=100010;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-6;
const double PI=acos(-1.0);

struct Tree{
    bool tag[26];
    int w[26];
    int l,r;
}tree[N<<2];

struct node{
    int v[26];
}zero;

int a[N];

void pushup(int u){
    rep(i,0,25) tree[u].w[i]=tree[u<<1].w[i]+tree[u<<1|1].w[i];
}

void pushdown(int u){
    if(tree[u].l==tree[u].r){
        return;
    }
    rep(i,0,25){
        if(tree[u].tag[i]){
            rep(j,0,25){
                tree[u<<1].tag[j]=0;
                tree[u<<1].w[j]=0;
                tree[u<<1|1].tag[j]=0;
                tree[u<<1|1].w[j]=0;
            }
            tree[u<<1].tag[i]=1;
            tree[u<<1|1].tag[i]=1;
            tree[u<<1].w[i]=tree[u<<1].r-tree[u<<1].l+1;
            tree[u<<1|1].w[i]=tree[u<<1|1].r-tree[u<<1|1].l+1;
            tree[u].tag[i]=0;
        }
    }
}

void build(int l,int r,int u){
    tree[u].l=l,tree[u].r=r;
    if(l==r){
        tree[u].w[a[l]]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,u<<1);
    build(mid+1,r,u<<1|1);
    pushup(u);
}

void update(int l,int r,int v,int u){
    if(tree[u].l>r||tree[u].r<l){
        return;
    }
    if(l<=tree[u].l&&r>=tree[u].r){
        rep(i,0,25){
            tree[u].w[i]=0;
            tree[u].tag[i]=0;
        }
        tree[u].tag[v]=1;
        tree[u].w[v]=tree[u].r-tree[u].l+1;
        return;
    }
    pushdown(u);
    int mid=(tree[u].l+tree[u].r)>>1;
    if(l<=mid) update(l,r,v,u<<1);
    if(r>mid) update(l,r,v,u<<1|1);
    pushup(u);
}

node query(int l,int r,int u){
    if(l<=tree[u].l&&r>=tree[u].r){
        node t;
        rep(i,0,25){
            t.v[i]=tree[u].w[i];
        }
        return t;
    }
    pushdown(u);
    int mid=(tree[u].l+tree[u].r)>>1;
    node t=zero;
    if(l<=mid){
        node tt=query(l,r,u<<1);
        rep(i,0,25){
            t.v[i]+=tt.v[i];
        }
    }
    if(r>mid){
        node tt=query(l,r,u<<1|1);
        rep(i,0,25){
            t.v[i]+=tt.v[i];
        }
    }
    return t;
}

void print(int u){
    pushdown(u);
    if(tree[u].l==tree[u].r){
        rep(i,0,25){
            if(tree[u].w[i]){
                cout<<(char)('a'+i);
                return;
            }
        }
    }
    print(u<<1);
    print(u<<1|1);
}

void solve(){
    int n,m;cin>>n>>m;
    rep(i,1,n){
        char x;cin>>x;
        a[i]=x-'a';
    }
    build(1,n,1);
    while(m--){
        int l,r,op;cin>>l>>r>>op;
        node t=query(l,r,1);
        if(op){ //升序
            rep(i,0,25){
                update(l,l+t.v[i]-1,i,1);
                l+=t.v[i];
            } 
        }
        else{ //降序
            per(i,25,0){
                update(l,l+t.v[i]-1,i,1);
                l+=t.v[i];
            }
        }
    }
    print(1);
}


int main(){
    ios::sync_with_stdio(0);cin.tie(0);
//    int t;cin>>t;while(t--)
    solve();
    return 0;
}