string

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

【数据范围】

对于40%的数据,n,m<=1000。

对于100%的数据,n,m<=100000

题解

image

这道题卡常卡得好严,打出正解也过不掉啊,我果然还是太菜了

就比暴力多二十分的代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath> 
#define N 100100
using namespace std; 

int n,m,tmp[27];
char s[N];

struct Segment_tree
{
	struct node
	{
		int l,r,sum,f;
	}T[N<<2];
	void pushup(int p){T[p].sum=T[p<<1].sum+T[p<<1|1].sum;}
	void build(int p,int x,int y,char v)
	{
		T[p].l=x;T[p].r=y;T[p].f=-1;
		if(x==y){if(s[x]==v)T[p].sum=1;return;}
		int mid=(x+y)>>1;
		build(p<<1,x,mid,v);
		build(p<<1|1,mid+1,y,v);
		pushup(p);
	}
	void pushdown(int p)
	{
		if(T[p].f==-1) return;
		T[p<<1].sum=(T[p<<1].r-T[p<<1].l+1)*T[p].f;
	    T[p<<1|1].sum=(T[p<<1|1].r-T[p<<1|1].l+1)*T[p].f;
	    T[p<<1].f=T[p<<1|1].f=T[p].f;
	    T[p].f=-1;
	}
	int query(int p,int x,int y)
	{
		int pl=T[p].l,pr=T[p].r;
		if(pl==x&&pr==y) return T[p].sum;
		pushdown(p);
		int mid=(pl+pr)>>1;
		if(y<=mid) return query(p<<1,x,y);
		else if(x>mid) return query(p<<1|1,x,y);
		return query(p<<1,x,mid)+query(p<<1|1,mid+1,y);
	}
	void set(int p,int x,int y,int v)
	{
		int pl=T[p].l,pr=T[p].r;
	    if(pl==x&&pr==y)
	    {
	        T[p].sum=(T[p].r-T[p].l+1)*v;
	        T[p].f=v;
	        return;
	    } 
	    pushdown(p);
	    int mid=(pl+pr)>>1;
	    if(y<=mid) set(p<<1,x,y,v);
	    else if(x>mid) set(p<<1|1,x,y,v);
	    else
	    {
	        set(p<<1,x,mid,v);
	        set(p<<1|1,mid+1,y,v);
	    }
	    pushup(p);
	}
	void get_ans(int p,int x,int y,char v)
	{
		if(x==y){if(T[p].sum)s[x]=v;return;}
		pushdown(p);
		int mid=(x+y)>>1;
		get_ans(p<<1,x,mid,v);
		get_ans(p<<1|1,mid+1,y,v);
		pushup(p);
	}
	
}st[27];

int main()
{
	scanf("%d%d%s",&n,&m,s+1);
	for(int i=0;i<26;i++) st[i].build(1,1,n,'a'+i);//对于每个字母,用一颗线段树维护 
	while(m--)
	{
		int l,r,opt;scanf("%d%d%d",&l,&r,&opt);
		for(int i=0;i<26;i++) tmp[i]=st[i].query(1,l,r);//先求出区间内字母i的个数
		for(int i=0;i<26;i++) st[i].set(1,l,r,0);//将区间清空 
		if(opt)//升序
		{
			int pos=l;
			for(int i=0;i<26;i++) if(tmp[i]) st[i].set(1,pos,pos+tmp[i]-1,1),pos+=tmp[i];
		}
		else//降序 
		{
			int pos=l;
			for(int i=25;i>=0;i--) if(tmp[i]) st[i].set(1,pos,pos+tmp[i]-1,1),pos+=tmp[i];
		}
	}
	for(int i=0;i<26;i++) st[i].get_ans(1,1,n,'a'+i);
	for(int i=1;i<=n;i++) printf("%c",s[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/XYZinc/p/7721872.html