题意
一个长度为n的字符串,有q条查询。
两种操作:
1. i,j,1 把字符串从i到j的部分升序排列
2. i,j,0把字符串从i到j的部分降序排列
求q次查询之后字符串的结果
思路
训练赛的时候这题没想出来怎么写,下来查了查题解。然后分析一波,终于理解了。
就是建立26棵线段树,对应每个字母,负责记录每个字母出现的位置。
每个T内ans记录的就是该字母出现的位置,而cnt统计我们要操作的那部分的那个字母出现了几次,
然后因为要对那个区间更新,所以对这个区间可以先用0覆盖,然后再根据cnt来重新更新(其实是计数排序)
几个需要注意的地方:
1.因为有用0覆盖的操作,lazy标记应该达成-1
2.update函数应该用赋值,而不是直接套用区间更新的模板在原节点的基础上加减
代码
#include<iostream>
#include<cmath>
#include<stack>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
#define Endl "\n"
typedef long long ll;
const int maxn=1e5+5;
const int mod=1e9+7;
using namespace std;
char s[maxn];
inline ll read()
{
ll x = 0, f = 1; char ch; ch = getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct sgt{
int ans[maxn<<2],lazy[maxn<<2];
void PushUp(int rt)
{
ans[rt]=ans[rt<<1]+ans[rt<<1|1];
return ;
}
void PushDown(int rt,int ln,int rn)//ln表示左子树元素结点个数,rn表示右子树结点个数
{
if (lazy[rt]!=-1)
{
lazy[rt<<1]=lazy[rt];
lazy[rt<<1|1]=lazy[rt];
ans[rt<<1]=lazy[rt]*ln;
ans[rt<<1|1]=lazy[rt]*rn;
lazy[rt]=-1;
}
}
void Update(int L,int R,int C,int l,int r,int rt)
{
if (L<=l&&r<=R)
{
ans[rt]=C*(r-l+1);
lazy[rt]=C;
return;
}
int mid=(l+r)>>1;
int left=rt<<1;
int right=left|1;
PushDown(rt,mid-l+1,r-mid);
if (L<=mid) Update(L,R,C,l,mid,left);
if (R>mid) Update(L,R,C,mid+1,r,right);
PushUp(rt);
}
//查询
ll Query(int L,int R,int l,int r,int rt)
{
if (L<=l&&r<=R)
return ans[rt];
int mid=(l+r)>>1;
int left=rt<<1;
int right=left|1;
PushDown(rt,mid-l+1,r-mid);//若更新只有点更新,不需要这句
ll ANS=0;
if (L<=mid) ANS+=Query(L,R,l,mid,left);
if (R>mid) ANS+=Query(L,R,mid+1,r,right);
PushUp(rt);
return ANS;
}
};
struct sgt T[26];
int cnt[26];
int n,q;
int main()
{
n=read(),q=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
T[s[i]-'a'].Update(i,i,1,1,n,1);
}
while(q--)
{
int a,b,key;
a=read(),b=read(),key=read();
if(key)
{
for(int i=0;i<26;i++)
cnt[i]=T[i].Query(a,b,1,n,1);
// cout<<"------test1----"<<endl;
// for(int i=0;i<26;i++)
// cout<<cnt[i]<<" ";
// cout<<endl;
for(int i=0;i<26;i++)
T[i].Update(a,b,0,1,n,1);
int x=a;
for(int i=0;i<26;i++)
if(cnt[i]!=0)
{
T[i].Update(x,x+cnt[i]-1,1,1,n,1);
x+=cnt[i];
}
}
else
{
for(int i=0;i<26;i++)
cnt[i]=T[i].Query(a,b,1,n,1);
// cout<<"------test2----"<<endl;
// for(int i=0;i<26;i++)
// cout<<cnt[i]<<" ";
// cout<<endl;
for(int i=0;i<26;i++)
T[i].Update(a,b,0,1,n,1);
int x=a;
for(int i=25;i>=0;i--)
if(cnt[i]!=0)
{
T[i].Update(x,x+cnt[i]-1,1,1,n,1);
x+=cnt[i];
}
}
// cout<<q<<Endl;
}
// cout<<"here1"<<Endl;
for(int i=1;i<=n;i++)
for(int j=0;j<26;j++)
if(T[j].Query(i,i,1,n,1))
printf("%c",j+'a');
// cout<<"here2"<<Endl;
return 0;
}