CodeForces 558E A Simple Task 线段树 桶排思想

CodeForces 558E A Simple Task 线段树 桶排思想

题意

给定长度不超过(10^5)的字符串(小写英文),和不超过(10^5)的操作。

每次操作对([L,R])区间的字符排序,(K = 1)表示升序,(K = 0) 表示降序。

分析

一般这种题可以转化着去做,即不要真的去排序。

但是考虑到此题的特殊性(字符集非常小),想到用桶排的思想。

对于一段区间,首先把在这段区间的某个字母全部拿出来(桶),然后依次按顺序放到区间里(排)。

到此题,相当于要进行区间修改和区间查询,想到用线段树即可。

开26个线段树表示字母的出现位置,对于查询([l,r]),从小到大排,若有(num)个,就排在([l + cur + num,l + cur + num-1])

如果是降序,那么反一下就好了。

代码

#include<bits/stdc++.h>
#define eps 1e-8
#define equals(a,b) (fabs(a - b) < eps)
using namespace std;

typedef long long ll;

const ll MOD = 1e9 + 7;

ll rd(){
	ll x = 0;
	int f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == -1) f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	} 
	return  x * f;
}

int cur;

struct SegmentTree{
	int n;
	vector<int> sum,tag;
	SegmentTree(){}
	SegmentTree(int n):n(n),sum(((n + 1) << 2)),tag(((n + 1) << 2),-1) {}
	int push_up(int i){
		sum[i] = sum[i << 1] + sum[i << 1|1];
	}
	void update(int i,int l,int r,int v){
		sum[i] = (r - l + 1) * v;
		tag[i] = v;
	}
	void push(int i,int l,int r){
		int mid = l + r >> 1;
		if(tag[i] != -1) {
			update(i << 1,l,mid,tag[i]);
			update(i << 1|1,mid + 1,r,tag[i]);
			tag[i] = -1;
		}
	}
	void update(int i,int l,int r,int L,int R,int v){
		if(l > R || r < L) return;
		if(l >= L && r <= R) return update(i,l,r,v);
		int mid = l + r >> 1;
		push(i,l,r);
		update(i << 1,l,mid,L,R,v);
		update(i << 1|1,mid + 1,r,L,R,v);
		push_up(i);
	} 
	int query(int i,int l,int r,int L,int R){
		if(l > R || r < L) return 0;
		if(l >= L && r <= R) return sum[i];
		int mid = l + r >> 1;
		push(i,l,r);
		return query(i << 1,l,mid,L,R) + query(i << 1|1,mid + 1,r,L,R); 
	}
};

char s[100005];
SegmentTree seg[26];

int main(){
	int n = rd();
	int m = rd();
	for(int i = 0;i < 26;i++)
		seg[i] = {n};
	scanf("%s",s);
	for(int i = 0;i < n;i++)
		seg[s[i] - 'a'].update(1,1,n,i + 1,i + 1,1);
	while(m--){
		cur = 0;
		int l = rd();
		int r = rd();
		int k = rd();
		if(k == 1) {
			for(int i = 0;i < 26;i++){
				int num = seg[i].query(1,1,n,l,r);
				if(!num) continue;
				seg[i].update(1,1,n,l,r,0);
				seg[i].update(1,1,n,l + cur,l + cur + num - 1,1);
				cur += num;
			}
		}
		else{
			for(int i = 25;i >= 0;i--){
				int num = seg[i].query(1,1,n,l,r);
				if(!num) continue;
				seg[i].update(1,1,n,l,r,0);
				seg[i].update(1,1,n,l + cur,l + cur + num - 1,1);
				cur += num;
			}
		}
	}
	for(int i = 0;i < n;i++){
		for(int j = 0;j < 26;j++){
			if(seg[j].query(1,1,n,i + 1,i  + 1)) {
				s[i] = 'a' + j;
				break;
			}
		}
	}
	printf("%s",s);
}
原文地址:https://www.cnblogs.com/hznumqf/p/14486853.html