CF 558E(A Simple Task-计数排序+线段树)

E. A Simple Task

time limit per test

5 seconds

memory limit per test

512 megabytes

input

standard input

output

standard output

This task is very simple. Given a string S of length n and q queries
each query is on the format i j k which
means sort the substring consisting of the characters from i to j in
non-decreasing order if k?=?1 or in non-increasing order if k?=?0.

Output the final string after applying the queries.

Input

The first line will contain two integers n,?q (1?≤?n?≤?105, 0?≤?q?≤?50?000),
the length of the string and the number of queries respectively.

Next line contains a string S itself. It contains only lowercase English letters.

Next q lines will contain three integers each i,?j,?k (1?≤?i?≤?j?≤?n).

Output

Output one line, the string S after applying the queries.

Sample test(s)

input

10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1

output

cbcaaaabdd

input

10 1
agjucbvdfk
1 10 1

output

abcdfgjkuv

Note

First sample test explanation:

计数排序,关键是如何维护

计算发现建26棵线段树,复杂度为O(m*26logN)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (400000+10)
#define MAXQ (50000+10)
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int n,q;

int l,r,v,_ans;
class Stree{
public:
	int mark[MAXN],tree[MAXN];
	Stree(){
		MEM(mark) MEM(tree)
	}
	void pushdown(int o,int L,int R)
	{
		if (L<R) if (mark[o]) mark[Lson]=mark[Rson]=mark[o],mark[o]=0;
	}
	void maintain(int o,int L,int R)
	{
		if (mark[o]) tree[o]=(R-L+1)*(mark[o]-1);
		else if (L<R) tree[o]=tree[Lson]+tree[Rson];
	}
	void set(int o,int L,int R)
	{
		if (l<=L&&R<=r) {
			mark[o]=v;
			maintain(o,L,R);
			return;
		}
		pushdown(o,L,R);
		int M=(L+R)>>1;
		if (l<=M) set(Lson,L,M);else maintain(Lson,L,M);
		if (M<r) set(Rson,M+1,R);else maintain(Rson,M+1,R);
		maintain(o,L,R);
	}
	void get_sum(int o,int L,int R)
	{

		if (l<=L&&R<=r)
		{
			_ans+=tree[o];
			return;
		}
		if (mark[o]) {
			_ans+=(min(r,R)-max(L,l)+1)*(mark[o]-1);
			return;
		}

		int M=(L+R)>>1;
		if (l<=M) get_sum(Lson,L,M);
		if (M<r) get_sum(Rson,M+1,R);
	}

}S[26];
char s[MAXN];

int cnt[26]={0};

int main()
{
//	freopen("E.in","r",stdin);
//	freopen(".out","w",stdout);

	scanf("%d%d%s",&n,&q,s);
	Rep(i,n) {
		l=r=i+1,v=2;
		S[s[i]-'a'].set(1,1,n);
	}
	For(qcase,q)
	{
		int b;
		scanf("%d%d%d",&l,&r,&b);

		v=1;
		Rep(i,26) {
			_ans=0;
			S[i].get_sum(1,1,n);
			cnt[i]=_ans;
			S[i].set(1,1,n);
		}
		v=2;
		if (b) //increasing
		{
			Rep(i,26)
			{
				if (!cnt[i]) continue;
				r=l+cnt[i]-1;
				S[i].set(1,1,n);
				l=r+1;
			}
		} else {
			Rep(i,26)
			{
				if (!cnt[i]) continue;
				l=r-cnt[i]+1;
				S[i].set(1,1,n);
				r=l-1;
			} 

		} 

	}
	For(i,n)
	{
		Rep(j,26)
		{
			l=r=i;_ans=0;
			S[j].get_sum(1,1,n);
			if (_ans) {
				s[i-1]='a'+j;
				break;
			}
		}
	} 

	printf("%s\n",s);

	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 15:01:22

CF 558E(A Simple Task-计数排序+线段树)的相关文章

Codeforces 558E A Simple Task (计数排序&amp;&amp;线段树优化)

题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memory limit per test512 megabytes inputstandard input outputstandard output This task is very simple. Given a string S of length n and q queries each quer

计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task

E. A Simple Task Problem's Link: http://codeforces.com/problemset/problem/558/E Mean: 给定一个字符串,有q次操作,每次操作将(l,r)内的字符升序或降序排列,输出q次操作后的字符串. analyse: 基本思想是计数排序. 所谓计数排序,是对一个元素分布较集中的数字集群进行排序的算法,时间复杂度为O(n),但使用条件很苛刻.首先对n个数扫一遍,映射出每个数字出现的次数,然后再O(n)扫一遍处理出:对于数字ai,

POJ 3468 A Simple Problem with Integers(线段树区间更新)

题目地址:POJ 3468 打了个篮球回来果然神经有点冲动..无脑的狂交了8次WA..居然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题.区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新.其他的均按线段树的来就行. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <math.h> #include <stac

HDU4267 A Simple Problem with Integers 线段树/树状数组

HDU4267 A Simple Problem with Integers  线段树/树状数组 2012长春网络赛A题 Problem Description Let A1, A2, ... , AN be N elements. You need to deal with two kinds of operations. One type of operation is to add a given number to a few numbers in a given interval. T

POJ3468_A Simple Problem with Integers(线段树/成段更新)

解题报告 题意: 略 思路: 线段树成段更新,区间求和. #include <iostream> #include <cstring> #include <cstdio> #define LL long long #define int_now int l,int r,int root using namespace std; LL sum[500000],lazy[500000]; void push_up(int root,int l,int r) { sum[ro

2014 Super Training #9 F A Simple Tree Problem --DFS+线段树

原题: ZOJ 3686 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686 这题本来是一个比较水的线段树,结果一个mark坑了我好几个小时..哎.太弱. 先DFS这棵树,树形结构转换为线性结构,每个节点有一个第一次遍历的时间和最后一次遍历的时间,之间的时间戳都为子树的时间戳,用线段树更新这段区间即可实现更新子树的效果,用到懒操作节省时间. 坑我的地方: update时,不能写成:tree[rt].mark = 1,

【POJ】3468 A Simple Problem with Integers ——线段树 成段更新 懒惰标记

A Simple Problem with Integers Time Limit:5000MS   Memory Limit:131072K Case Time Limit:2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each

POJ3468__A Simple Problem with Integers (线段树)

本文出自blog.csdn.net/svitter --我大C++的指针岂是尔等能够简单领悟! 题意 给N个节点,标号A1~An,然后有Q个操作,操作分为Q i j,查询i,j间的区间和.C i j k,i到j个数字,每个数字增加k,并且输出. 输入输出分析 给N,Q,然后跟操作.注意判断Q,C使用scanf("%s"). 测试数据: Sample Input 10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 4 Samp

[线段树] codeforces 558E. A Simple Task

题意: 给一个长度n的字符串,q次操作,每次操作把[l,r]排序,k=0非递增,k=1非递减. 题解: 采用计数排序的复杂度是O(n?q),无法通过,但有所启示. 可以看出计数就是区间求和,排序就是区间更新,可以用线段树维护. 做法是建立26棵线段树,第i棵树维护第i个字母的位置信息. 计数时,在26棵线段树内分别做一次查询,排序时根据递增还是递减,把相应的区间赋值为相应的字母. #include<bits/stdc++.h> #define lson rt<<1,l,mid #d