1. 程式人生 > 實用技巧 >【NOIP模擬題目】string

【NOIP模擬題目】string

題目描述:

給定一個由小寫字母組成的字串s。
有m次操作,每次操作給定3個引數l,r,x。
如果x = 1,將s[l] s[r]升序排序;
如果x = 0,將s[l] s[r]降序排序。
你需要求出最終序列。

輸入格式:

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

輸出格式:

一行一個字串表示答案。

輸入樣例:

5 2
cabcd
1 3 1
3 5 0

輸出樣例:

abdcc

資料範圍:

對於100%的資料,n,m ≤ 100000。


思路

  • 數字代替字母,每一次操作取出區間所有數字再填入,線段樹實現
  • 有關清零,每一次getcol就順便將lazy標記清零,但不能在f陣列加時清零,會錯
  • 這篇題解似乎比較詳細

程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 100005
using namespace std;
struct fdfdfd{int l,r,val;}a[maxn<<2];
int n,m,f[30];
string st;
void pushup(int x){if(a[x<<1].val==a[x<<1|1].val) a[x].val=a[x<<1].val;}
void build(int x,int left,int right)
{
	a[x].l=left; a[x].r=right;
	if(left==right) {a[x].val=st[left-1]-'a'+1; return;}
	int mid=(left+right)>>1;
	build(x<<1,left,mid); build(x<<1|1,mid+1,right);
	pushup(x);
}
void getcol(int x,int left,int right)
{
	if(a[x].r<left||a[x].l>right) return;
	if(left<=a[x].l&&right>=a[x].r&&a[x].val) {f[a[x].val]+=a[x].r-a[x].l+1; return;}
	if(a[x].val) a[x<<1].val=a[x<<1|1].val=a[x].val;
	getcol(x<<1,left,right); getcol(x<<1|1,left,right);
}
void modify(int x,int left,int right,int d)
{
	if(a[x].r<left||a[x].l>right) return;
	if(left<=a[x].l&&right>=a[x].r) {a[x].val=d; return;}
	if(a[x].val) a[x<<1].val=a[x<<1|1].val=a[x].val,a[x].val=0;
	modify(x<<1,left,right,d); modify(x<<1|1,left,right,d);
	pushup(x);
}
void print(int x)
{
	if(a[x].val)
	{
		for(int i=a[x].l;i<=a[x].r;++i) printf("%c",a[x].val+'a'-1);
		return;
	}
	print(x<<1); print(x<<1|1);
}
int main()
{
    scanf("%d%d",&n,&m); cin>>st; build(1,1,n);
    for(int i=1,l,r,x;i<=m;++i)
    {
    	scanf("%d%d%d",&l,&r,&x);
    	memset(f,0,sizeof(f));
    	getcol(1,l,r);
    	if(x)
    	{
    		for(int j=1;j<=26;++j)
    			if(f[j]) modify(1,l,l+f[j]-1,j),l+=f[j];
    	}
    	else
    	{
    		for(int j=26;j>=1;--j)
    			if(f[j]) modify(1,l,l+f[j]-1,j),l+=f[j];
    	}
    }
    print(1);
    return 0;
}