题解 - CF558E A Simple Task

题解 - C F 558 E   A   S i m p l e   T a s k \mathrm{CF558E \ A \ Simple \ Task}

吐槽一下:

  • 这道题目足足做了我 3 3 个小时,我 s t m stm 真的要吐血了。

题目意思

就是给你一长为 n ( 1 0 5 ) n(\leq 10^5) 个小写字母序列,支持两种操作:

  • ( l , r , 0 ) (l,r,0) :将 [ l , r ] [l,r] 升序
  • ( l , r , 1 ) (l,r,1) :将 [ l , r ] [l,r] 倒序

求出 m ( 1 0 5 ) m(\leq 10^5) 次操作后的序列。

S o l \mathrm{Sol}

  • 可以说是一道经典套路题吧
  • 我们首先建 26 26 棵线段树维护每一个字母,相当于对于升序我们只要对于这段区间里的字母按 a z \mathrm{a-z} 的顺序依次加入,不停更新加入左端点即可,右端点即为左端点加这个字母的数量。倒序也同理,只要 z a \mathrm{z-a} 的顺序即可。
  • 然后就是线段树的基本操作了(嘻嘻嘻,我调了半年。
  • 说句实话:对于大多数题目,套路就是硬道理。。。

C o d e \mathrm{Code}

#include <bits/stdc++.h>
using namespace std;
 
inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}
 
const int N=1e5+5;
 
int n,m,ans;
char ch[100001],res[100001];
 
struct seg
{
	int tr[31][400001],laz[31][400001];
	inline void init()
	{
		for ( int i=1;i<=26;i++ )  
			memset(laz[i],-1,sizeof(laz[i]));
	}
	inline void build(int rt,int l,int r)
	{
		if(l==r)
		{
			tr[ch[l]-'a'+1][rt]=1;
			return;
		}
		int mid=(l+r)/2;
		build(rt<<1,l,mid);
		build(rt<<1|1,mid+1,r);
		for ( int i=1;i<=26;i++ ) 
			tr[i][rt]=(tr[i][rt<<1]+tr[i][rt<<1|1]);
	}
	inline void push_down(int rt,int l,int r,int col)
	{
		if(laz[col][rt]!=-1)
		{
			tr[col][rt]=laz[col][rt]*(r-l+1);
			int mid=(l+r)/2;
			tr[col][rt<<1]=laz[col][rt]*(mid-l+1);
			tr[col][rt<<1|1]=laz[col][rt]*(r-mid);
			laz[col][rt<<1]=laz[col][rt];
			laz[col][rt<<1|1]=laz[col][rt];
			laz[col][rt]=-1;
		}
	}
	inline void update(int rt,int l,int r,int ll,int rr,int col,int v)
	{
		if(ll<=l&&r<=rr)
		{
			tr[col][rt]=v*(r-l+1);
			laz[col][rt]=v;
			return;
		}
		push_down(rt,l,r,col);
		int mid=(l+r)/2;
		if(ll<=mid) update(rt<<1,l,mid,ll,rr,col,v);
		if(rr>mid) update(rt<<1|1,mid+1,r,ll,rr,col,v);
		tr[col][rt]=tr[col][rt<<1]+tr[col][rt<<1|1];
	}
	inline int query(int rt,int l,int r,int ll,int rr,int col)
	{
		if(ll<=l&&r<=rr) return tr[col][rt];
		push_down(rt,l,r,col);
		int mid=(l+r)/2;
		int sum=0;
		if(ll<=mid) sum+=query(rt<<1,l,mid,ll,rr,col);
		if(rr>mid) sum+=query(rt<<1|1,mid+1,r,ll,rr,col);
		return sum;
	}
	inline void print(int rt,int l,int r)
	{
		if(l==r)
		{
			for ( int i=1;i<=26;i++ ) 
				if(tr[i][rt]) 
				{
					res[l]='a'+i-1;
					break;
				}
			return;
		}
		for ( int i=1;i<=26;i++ ) push_down(rt,l,r,i);
		int mid=(l+r)/2;
		print(rt<<1,l,mid);
		print(rt<<1|1,mid+1,r);
	}				
};
seg T;
 
int main()
{
	n=read();
	m=read();
	scanf("%s",ch+1);
	T.init();
	T.build(1,1,n);
	for (;m--;)
	{
		int op,x,y;
		x=read(),y=read(),op=read();
		if(op==1)
		{
			int tmp=x-1;
            for ( int j=1;j<=26;j++ )
			{
                int cas=T.query(1,1,n,x,y,j);
                if(!cas)continue;
                T.update(1,1,n,x,y,j,0);
                T.update(1,1,n,tmp+1,tmp+cas,j,1);
				tmp=tmp+cas;
            }
		}
		else
		{
			int lp=x-1;
			for ( int j=26;j>=1;j-- )
			{
				int sum=T.query(1,1,n,x,y,j);
				if(!sum) continue;
				T.update(1,1,n,x,y,j,0);
				T.update(1,1,n,lp+1,lp+sum,j,1);
				lp+=sum;

			}
		}
	}
	T.print(1,1,n);
	for ( int i=1;i<=n;i++ ) putchar(res[i]);
	return 0;
}
/*
10 5
abacdabcda
7 10 0
5 8 1
1 4 0
3 6 0
7 10 1
*/

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/104910912