• 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);
    }
    
  • 相关阅读:
    Silverlight Toolkit ListBoxDragDropTarget学习笔记
    函数指针和指针函数(转)
    面试题_反转链表
    C++中的异或运算符^
    面试题_旋转字符串
    面试题_寻找丑数
    模拟一个简单的基于tcp的远程关机程序
    管理指针成员
    赫夫曼树编码问题
    堆的基本操作
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14486853.html
Copyright © 2020-2023  润新知