[Contest on 2020.11.8] 排序

( ext{Descrption})

题目描述

​ 给定一个仅由小写字母组成的字符串s。
​ 有m次操作,每次操作有3个参数L,R,opt。
​ 如果opt为1,那么将区间[L,R]内的字符按升序(即从'a'到'z')排列。
​ 如果opt为0,那么将区间[L,R]内的字符按降序(即从'z'到'a')排列。
​ 求m次操作后的字符串。

输入格式

​ 第一行两个正整数 n 和 m,分别表示字符串的长度和操作次数。
​ 接下来一行一个长度为 n 的字符串。
​ 接下来 m 行每行 3 个正整数 L,R,opt_i,表示一个操作。

输出格式

输出一行一个长度为n的字符串,表示m次操作后的字符串。

样例输入

5 2
cabcd
1 3 1
3 5 0

样例输出

abdcc

数据规模与约定

对于 40% 的数据, 1≤n≤1000 , 0≤m≤1000 。
对于 100% 的数据, 1≤n≤10^5 , 0≤m≤10^5 , 0≤opt≤1 , 1≤L≤R≤n 。

( ext{Solution})

感觉很神奇。

其实关键就是这里的权值只有 (26) 种。

我们可以从小到大枚举字母分界线 (ch),大于等于 (ch) 的字母赋为 (1),反之为 (0)。然后依次进行 (m) 次排序(以 (0,1) 为关键字),然后我们可以 (mathcal O(log n)) 地查询某个位置是否大于等于 (ch),如果是就先赋为 (ch),这样下一次当前的 (ch) 变成 (0),不会再被赋值,后面的字母也能被赋值。

( ext{Code})

#include <cstdio>
#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
#define print(x,y) write(x),putchar(y)

int read() {
    int x=0,f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}

void write(int x) {
    if(x<0) return (void)(putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}

const int maxn=1e5+5;

int n,m,L[maxn],R[maxn],op[maxn],t[maxn<<2];
char s[maxn],ans[maxn];

void pushDown(int o,int l,int r) {
	int mid=l+r>>1;
	if(t[o]==r-l+1) t[o<<1]=mid-l+1,t[o<<1|1]=r-mid;
	else if(t[o]==0) t[o<<1]=t[o<<1|1]=0;
}

void modify(int o,int l,int r,int L,int R,int k) {
	if(l>R||r<L) return;
	if(l>=L&&r<=R) {t[o]=k*(r-l+1); return;}
	int mid=l+r>>1;
	pushDown(o,l,r);
	modify(o<<1,l,mid,L,R,k); modify(o<<1|1,mid+1,r,L,R,k);
	t[o]=t[o<<1]+t[o<<1|1];
}

int query(int o,int l,int r,int L,int R) {
	if(l>R||r<L) return 0;
	if(l>=L&&r<=R) return t[o];
	int mid=l+r>>1;
	pushDown(o,l,r);
	return query(o<<1,l,mid,L,R)+query(o<<1|1,mid+1,r,L,R);
}

void work() {
	rep(i,1,m) {
		int cnt=query(1,1,n,L[i],R[i]);
		if(cnt==R[i]-L[i]+1||cnt==0) continue;
		if(op[i]) modify(1,1,n,L[i],R[i]-cnt,0),modify(1,1,n,R[i]-cnt+1,R[i],1);
		else modify(1,1,n,L[i],L[i]+cnt-1,1),modify(1,1,n,L[i]+cnt,R[i],0);
	}
}

int main() {
	n=read(),m=read();
	scanf("%s",s+1);
	rep(i,1,m) L[i]=read(),R[i]=read(),op[i]=read();
	for(char ch='a';ch<='z';++ch) {
		rep(i,1,n) modify(1,1,n,i,i,s[i]>=ch);
		work();
		rep(i,1,n) if(query(1,1,n,i,i)) ans[i]=ch;
	}
	rep(i,1,n) putchar(ans[i]); puts("");
	return 0;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/13944611.html