概述
题解 - C F 558 E A S i m p l e T a s k mathrm{CF558E A Simple Task} CF558E A Simple Task
吐槽一下:
- 这道题目足足做了我 3 3 3个小时,我 s t m stm stm真的要吐血了。
题目意思
就是给你一长为 n ( ≤ 1 0 5 ) n(leq 10^5) n(≤105)个小写字母序列,支持两种操作:
- ( l , r , 0 ) (l,r,0) (l,r,0):将 [ l , r ] [l,r] [l,r]升序
- ( l , r , 1 ) (l,r,1) (l,r,1):将 [ l , r ] [l,r] [l,r]倒序
求出 m ( ≤ 1 0 5 ) m(leq 10^5) m(≤105)次操作后的序列。
S o l mathrm{Sol} Sol
- 可以说是一道经典套路题吧
- 我们首先建 26 26 26棵线段树维护每一个字母,相当于对于升序我们只要对于这段区间里的字母按 a − z mathrm{a-z} a−z的顺序依次加入,不停更新加入左端点即可,右端点即为左端点加这个字母的数量。倒序也同理,只要 z − a mathrm{z-a} z−a的顺序即可。
- 然后就是线段树的基本操作了(嘻嘻嘻,我调了半年。
- 说句实话:对于大多数题目,套路就是硬道理。。。
C o d e mathrm{Code} 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
*/
最后
以上就是着急铅笔为你收集整理的题解 - CF558E A Simple Task题解 - C F 558 E A S的全部内容,希望文章能够帮你解决题解 - CF558E A Simple Task题解 - C F 558 E A S所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复