CF558E A Simple Task/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;
}