cf #312 E. A Simple Task (线段树+计数排序)

题目:http://codeforces.com/contest/558/problem/E

题意:给你一个字符串s,|s|<=1e5。有q(q<50 000)次操作,有2种操作类型。①将给定区间的字符按非降序排序②将给定区间的字符按非升序排序。

分析:

计数排序:先统计区间内每种字符的个数,然后按顺序将字符分配。

例如bccasabdass

a有3个 b有2个 c有2个 d有1个 s有3个

按顺序分配之后就是aaabbccdsss,就已经排好序了。


现在用线段树的每个节点保存区间内每种字符的个数,如果操作将一段区间变为升序的话,先统计区间各字符的个数,然后按顺序分配给线段树中的合法区间,并且和以前一样用懒惰标记方法处理区间更新。


代码:

#include <bits/stdc++.h>
using namespace std;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 1e5+6;
char str[maxn];

struct node
{
	int num[26];
	int lazy;
}tree[maxn<<2];
int n,q;

void pushdown(int l,int r,int rt)
{
	if(tree[rt].lazy==1)  //increasing 
	{
		memset(tree[rt<<1].num,0,sizeof(int)*26);
		memset(tree[rt<<1|1].num,0,sizeof(int)*26);
		
		int m=(l+r)>>1;
		int rangeL=m-l+1;
		int cnt=0,i;
		for(i=0;i<26;i++)
		{
			if(cnt+tree[rt].num[i]>=rangeL)
			{
				tree[rt<<1].num[i]=rangeL-cnt;
				tree[rt<<1|1].num[i]=tree[rt].num[i]-(rangeL-cnt);
				i++;
				break;
			}
			cnt+=tree[rt].num[i];
			tree[rt<<1].num[i]=tree[rt].num[i];
		}
		for(;i<26;i++)
			tree[rt<<1|1].num[i]=tree[rt].num[i];
//		printf("[%d %d] [%d %d]\n",l,m,m+1,r);
//		for(int i=0;i<26;i++)
//		{
//			int t=tree[rt<<1].num[i];
//			while(t--)
//				putchar('a'+i);
//		}
//		printf("|");
//		for(int i=0;i<26;i++)
//		{
//			int t=tree[rt<<1|1].num[i];
//			while(t--)
//				putchar('a'+i);
//		}
//		printf("\n");
		tree[rt<<1].lazy=tree[rt<<1|1].lazy=1;
		tree[rt].lazy=-1;
	}
	else if(tree[rt].lazy==0)  //decreasing
	{
		memset(tree[rt<<1].num,0,sizeof(int)*26);
		memset(tree[rt<<1|1].num,0,sizeof(int)*26);
		
		int m=(l+r)>>1;
		int rangeL=m-l+1;
		int cnt=0,i;
		for(i=25;i>=0;i--)
		{
			if(cnt+tree[rt].num[i]>=rangeL)
			{
				tree[rt<<1].num[i]=rangeL-cnt;
				tree[rt<<1|1].num[i]=tree[rt].num[i]-(rangeL-cnt);
				i--;
				break;
			}
			cnt+=tree[rt].num[i];
			tree[rt<<1].num[i]=tree[rt].num[i];
		}
		for(;i>=0;i--)
			tree[rt<<1|1].num[i]=tree[rt].num[i];
		tree[rt<<1].lazy=tree[rt<<1|1].lazy=0;
		tree[rt].lazy=-1;
	}
	return ;
}

void pushup(int rt)
{
	for(int i=0;i<26;i++)
		tree[rt].num[i]=tree[rt<<1].num[i]+tree[rt<<1|1].num[i];		
}
void build(int pos,char ch,int l,int r,int rt)
{
	tree[rt].lazy=-1;
	if(l==r)
	{
		memset(tree[rt].num,0,sizeof(int)*26);
		tree[rt].num[ch-'a']++;
		return ;
	}
	int m=(l+r)>>1;
	if(pos<=m)
		build(pos,ch,lson);
	else
		build(pos,ch,rson);
	pushup(rt);
}
int buf[26];
void query(int L,int R,int l,int r,int rt)
{
	if(L<=l && r<=R)
	{
		for(int i=0;i<26;i++)
			buf[i]+=tree[rt].num[i];
		return ;
	}
	pushdown(l,r,rt);
	int m=(l+r)>>1;
	if(L<=m)
		query(L,R,lson);
	if(R>m)
		query(L,R,rson);
	pushup(rt);
}
void Q(int L,int R)
{
	memset(buf,0,sizeof(buf));
	query(L,R,1,n,1);
}
void update1(int L,int R,int l,int r,int rt)
{
	if(L<=l && r<=R)
	{
		int range=r-l+1,cnt=0;
		memset(tree[rt].num,0,sizeof(int)*26);
		for(int i=0;i<26;i++)
		{
			if(cnt+buf[i]>=range)
			{
				tree[rt].num[i]+=range-cnt;
				buf[i]-=(range-cnt);
				break;
			}
			tree[rt].num[i]=buf[i];
			cnt+=buf[i];
			buf[i]=0;
		}
		tree[rt].lazy=1;
		return ;
	}
	pushdown(l,r,rt);
	int m=(l+r)>>1;
	if(L<=m)
		update1(L,R,lson);
	if(R>m)
		update1(L,R,rson);
	pushup(rt);
}

void update0(int L,int R,int l,int r,int rt)
{
	if(L<=l && r<=R)
	{
		int range=r-l+1,cnt=0;
		memset(tree[rt].num,0,sizeof(int)*26);
		for(int i=25;i>=0;i--)
		{
			if(cnt+buf[i]>=range)
			{
				tree[rt].num[i]+=range-cnt;
				buf[i]-=(range-cnt);
				break;
			}
			tree[rt].num[i]=buf[i];
			cnt+=buf[i];
			buf[i]=0;
		}
		tree[rt].lazy=0;
		return ;
	}
	pushdown(l,r,rt);
	int m=(l+r)>>1;
	if(L<=m)
		update0(L,R,lson);
	if(R>m)
		update0(L,R,rson);
	pushup(rt);
}

char getChar(int pos,int l,int r,int rt)
{
	if(l==r)
	{
		for(int i=0;i<26;i++)
			if(tree[rt].num[i])
				return 'a'+i;
		return '*';
	}
	pushdown(l,r,rt);
	int m=(l+r)>>1;
	if(pos<=m)
		return	getChar(pos,lson);
	else
		return getChar(pos,rson);
	pushup(rt);
}


int main()
{
	int i,j,k;
	scanf("%d%d",&n,&q);
	scanf("%s",str);
	for(int i=0;str[i];i++)
		build(i+1,str[i],1,n,1);
//	for(int i=0;str[i];i++)
//	{
//		putchar(getChar(i+1,1,n,1));
//	}
//	printf("\n");
	while(q--)
	{
		scanf("%d%d%d",&i,&j,&k);
		Q(i,j);
		if(k==1)
			update1(i,j,1,n,1);
		else
			update0(i,j,1,n,1);
//		for(int i=0;str[i];i++)
//		{
//			putchar(getChar(i+1,1,n,1));
//		}
//		printf("\n");
//		int x;
//		while(cin>>x)
//		{
//			putchar(getChar(x,1,n,1));
//		}
	}
	for(int i=1;i<=n;i++)
		putchar(getChar(i,1,n,1));
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值