题目大意
给定一个长度不超过10^5的字符串(小写英文字母),和不超过5000个操作。每个操作 L R K 表示给区间[L,R]的字符串排序,K=1为升序,K=0为降序。最后输出最终的字符串。
题解
我们做过luogu2828,那里我们无法对一段数字序列进行具体排序,那么这道题我们就要考虑其独有的特点。字母只有26个!所以我们对每个字母维护一个key值为下标,值为在下标范围内该字母出现次数的权值线段树即可,修改查询都很方便。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 100010, MAX_ALPHA = 30;
int N;
int OrgData[MAX_N];
int ValPosCnt[MAX_ALPHA][MAX_N];
struct RangeTree
{
private:
static const int MAX_NODE = MAX_N * 4;
int Sum[MAX_NODE], Cover[MAX_NODE];
void PushDown(int cur, int l, int r)
{
if(Cover[cur] != -1)
{
Cover[cur * 2] = Cover[cur * 2 + 1] = Cover[cur];
int mid = (l + r) / 2;
Sum[cur * 2] = (mid - l + 1) * Cover[cur];
Sum[cur * 2 + 1] = (r - mid) * Cover[cur];
Cover[cur] = -1;
}
}
void PullUp(int cur)
{
Sum[cur] = Sum[cur * 2] + Sum[cur * 2 + 1];
}
void Init(int cur, int l, int r, int *a)
{
if(l == r)
{
Sum[cur] = a[l];
return;
}
int mid = (l + r) / 2;
Init(cur * 2, l, mid, a);
Init(cur * 2 + 1, mid + 1, r, a);
PullUp(cur);
}
int Query_Update(int cur, int curL, int curR, int askL, int askR, int cover)
{
if(askL <= curL && curR <= askR)
{
int ans = Sum[cur];
Sum[cur] = (curR - curL + 1) * cover;
Cover[cur] = cover;
return ans;
}
PushDown(cur, curL, curR);
int mid = (curL + curR) / 2, ans = 0;
if(askL <= mid)
ans += Query_Update(cur * 2, curL, mid, askL, askR, cover);
if (askR > mid)
ans += Query_Update(cur * 2 + 1, mid + 1, curR, askL, askR, cover);
PullUp(cur);
return ans;
}
void OutPut(int cur, int l, int r, int *a, int val)
{
if(Sum[cur] == r - l + 1)
{
for (int i = l; i <= r; i++)
a[i] = val;
return;
}
PushDown(cur, l, r);
int mid = (l + r) / 2;
if(Sum[cur * 2])
OutPut(cur * 2, l, mid, a, val);
if (Sum[cur * 2 + 1])
OutPut(cur * 2 + 1, mid + 1, r, a, val);
}
public:
RangeTree()
{
memset(Cover, -1, sizeof(Cover));
}
void Init(int *a)
{
Init(1, 1, N, a);
}
int Query_Update(int l, int r, int cover)
{
return Query_Update(1, 1, N, l, r, cover);
}
void OutPut(int *a, int val)
{
OutPut(1, 1, N, a, val);
}
}g[MAX_ALPHA];
int main()
{
int opCnt;
scanf("%d%d\n", &N, &opCnt);
for (int i = 1; i <= N; i++)
{
char c;
scanf("%c", &c);
OrgData[i] = c - 'a' + 1;
}
for (int i = 1; i <= N; i++)
ValPosCnt[OrgData[i]][i] += 1;
for (int i = 1; i <= 26; i++)
g[i].Init(ValPosCnt[i]);
while(opCnt--)
{
int l, r, op;
scanf("%d%d%d", &l, &r, &op);
switch(op)
{
int prevR, prevL, num;
case 1:
prevR = l - 1;
for (int i = 1; i <= 26; i++)
{
num = g[i].Query_Update(l, r, 0);
if (num)
{
g[i].Query_Update(prevR + 1, prevR + num, 1);
prevR = prevR + num;
}
}
break;
case 0:
prevL = r + 1;
for (int i = 1; i <= 26; i++)
{
num = g[i].Query_Update(l, r, 0);
if (num)
{
g[i].Query_Update(prevL - num, prevL - 1, 1);
prevL = prevL - num;
}
}
break;
}
}
static int ans[MAX_N];
memset(ans, 0, sizeof(ans));
for (int i = 1; i <= 26; i++)
g[i].OutPut(ans, i);
for (int i = 1; i <= N; i++)
printf("%c", ans[i] + 'a' - 1);
printf("\n");
return 0;
}