[CSP-S模擬測試]:string(線段樹)

題目描述

給定一個由小寫字母組成的字符串$s$。html

有$m$次操做,每次操做給定$3$個參數$l,r,x$。c++

若是$x=1$,將$s[l]~s[r]$升序排序;算法

若是$x=0$,將$s[l]~s[r]$降序排序。ui

你須要求出最終序列。spa


輸入格式

第一行兩個整數$n,m$。
第二行一個字符串$s$。
接下來m行每行三個整數$l,r,x$。
htm


輸出格式

一行一個字符串表示答案。blog


樣例

樣例輸入排序

5 2
cabcd
1 3 1
3 5 0
字符串

樣例輸出get

abdcc


數據範圍與提示

對於$40\%$的數據,$n,m\leqslant 1,000$。
對於$100\%$的數據,$n,m\leqslant 100,000$。


題解

看到這道題,我就想到了:[BZOJ4552]:[Tjoi2016&Heoi2016]排序(桶排序)

然而,那道題我使用桶排序卡過的,時限仍是$6,000ms$,因此我當場懵逼,線段樹是確定看出來了,可是不知道該怎麼操做……

打題必定要打正解挖~

$40\%$算法:

直接用$sort$搞就行了,重載一下運算符,我以爲我說的每一句都是廢話……

桶排一分也不能多拿(萬惡的出題人)。

時間複雜度:

  $\Theta(m\times n)$(桶排序)。

  $\Theta( m\times n\log n)$(快排)。

指望得分:$40$分。

$100\%$算法:

由於這道題串中只有26個字母,因此就好說多了,用線段樹維護區間內$a~z$的個數,每次修改拆成26個修改就好了。

時間複雜度:$\Theta(26\times m\times \log n)$。

指望得分:$100$分。


代碼時刻

$40\%$算法:

#include<bits/stdc++.h>
using namespace std;
int n,m,l,r;
bool x;
int a[100001];
char ch[100001];
int t[50];
int st,ed;
void change1()
{
	register int maxn=0,minn=20020923,lft=l;
	for(int i=l;i<=r;i++)
	{
		t[a[i]]++;
		maxn=max(maxn,a[i]);
		minn=min(minn,a[i]);
	}
	for(register int i=minn;i<=maxn;i++)
		while(t[i])
		{
			a[lft++]=i;
			t[i]--;
		}
}
void change2()
{
	int maxn=0,minn=20020923,lft=l;
	for(register int i=l;i<=r;i++)
	{
		t[a[i]]++;
		maxn=max(maxn,a[i]);
		minn=min(minn,a[i]);
	}
	for(register int i=maxn;i>=minn;i--)
		while(t[i])
		{
			a[lft++]=i;
			t[i]--;
		}
}

int main()
{
	st=clock();
	scanf("%d%d%s",&n,&m,ch+1);
	for(register int i=1;i<=n;i++)
		a[i]=ch[i]-'a'+1;
	while(m--)
	{
		scanf("%d%d%d",&l,&r,&x);
		if(x)change1();
		else change2();
	}
	for(register int i=1;i<=n;i++)
		printf("%c",(char)a[i]+'a'-1);
	return 0;
}

$100\%$算法:

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
int n,m;
char ch[100001];
int tr[400001];
int flag[30];
void pushup(int x){if(tr[L(x)]==tr[R(x)])tr[x]=tr[L(x)];}
void pushdown1(int x){if(tr[x])tr[L(x)]=tr[R(x)]=tr[x];}
void pushdown2(int x){if(tr[x])tr[L(x)]=tr[R(x)]=tr[x];tr[x]=0;}
void build(int x,int l,int r)
{
	if(l==r){tr[x]=ch[l]-'a'+1;return;}
	int mid=(l+r)>>1;
	build(L(x),l,mid);
	build(R(x),mid+1,r);
	pushup(x);
}
void ask(int x,int l,int r,int L,int R)
{
	if(r<L||R<l)return;
	if(L<=l&&r<=R&&tr[x]){flag[tr[x]]+=r-l+1;return;}
	int mid=(l+r)>>1;
	pushdown1(x);
	ask(L(x),l,mid,L,R);
	ask(R(x),mid+1,r,L,R);
}
void change(int x,int l,int r,int L,int R,int v)
{
	if(r<L||R<l)return;
	if((L<=l&&r<=R)||tr[x]==v){tr[x]=v;return;}
	int mid=(l+r)>>1;
	pushdown2(x);
	change(L(x),l,mid,L,R,v);
	change(R(x),mid+1,r,L,R,v);
	pushup(x);
}
void print(int x,int l,int r)
{
	if(tr[x]){for(int i=l;i<=r;i++)printf("%c",(char)tr[x]+'a'-1);return;}
	int mid=(l+r)>>1;
	print(L(x),l,mid);
	print(R(x),mid+1,r);
}
int main()
{
	scanf("%d%d%s",&n,&m,ch+1);
	build(1,1,n);
	while(m--)
	{
		int l,r,x;
		scanf("%d%d%d",&l,&r,&x);
		memset(flag,0,sizeof(flag));
		ask(1,1,n,l,r);
		if(x)for(int i=1;i<=26;i++){change(1,1,n,l,l+flag[i]-1,i);l+=flag[i];}
		else for(int i=26;i>=1;i--){change(1,1,n,l,l+flag[i]-1,i);l+=flag[i];}
	}
	print(1,1,n);
	return 0;
}

rp++

相關文章
相關標籤/搜索