For each letter from 'a' to 'z', we create a separate segment tree. Thus, there are ALPHABET=26 trees in total, each supporting sum queries and multiple updates.
#define MAX 100010
#define ALPHABET 26
struct node
{
int sum, add;
} SegTree[4*MAX][ALPHABET];Declare an array to count the number of occurrences of each letter.
Build 26 segment trees based on the string s — one for each letter of the Latin alphabet.
void build(int v, int lpos, int rpos)
{
if (lpos == rpos)
{
SegTree[v][s[lpos] - 'a'].sum = 1;
for (int i = 0; i < ALPHABET; i++)
SegTree[v][i].add = -1;
}
else
{
int mid = (lpos + rpos) / 2;
build(v * 2, lpos, mid);
build(v * 2 + 1, mid + 1, rpos);
for (int i = 0; i < ALPHABET; i++)
{
SegTree[v][i].sum =
SegTree[v * 2][i].sum + SegTree[v * 2 + 1][i].sum;
SegTree[v][i].add = -1;
}
}
}The vertex v corresponds to the segment [lpos,rpos], with mid=(lpos+rpos)/2. Perform a push operation for this vertex in the segment tree with index ver.
void Push(int v, int lpos, int mid, int rpos, int ver)
{
if (SegTree[v][ver].add != -1)
{
SegTree[2 * v][ver].add = SegTree[v][ver].add;
SegTree[2 * v][ver].sum = (mid - lpos + 1) * SegTree[v][ver].add;
SegTree[2 * v + 1][ver].add = SegTree[v][ver].add;
SegTree[2 * v + 1][ver].sum = (rpos - mid) * SegTree[v][ver].add;
SegTree[v][ver].add = -1;
}
}The vertex v corresponds to the segment [lpos,rpos]. In the segment tree with index ver, set the value val for all elements with indices from left to right.
void SetValue(int v, int lpos, int rpos, int left, int right,
int val, int ver)
{
if (left > right) return;
if ((lpos == left) && (rpos == right))
{
SegTree[v][ver].add = val;
SegTree[v][ver].sum = (right - left + 1) * val;
return;
}
int mid = (lpos + rpos) / 2;
Push(v, lpos, mid, rpos, ver);
SetValue(2 * v, lpos, mid, left, min(mid, right), val, ver);
SetValue(2 * v + 1, mid + 1, rpos, max(left, mid + 1), right,
val, ver);
SegTree[v][ver].sum =
SegTree[2 * v][ver].sum + SegTree[2 * v + 1][ver].sum;
}The vertex v corresponds to the segment [lpos,rpos]. Find the sum of elements in the range [left;right] in the segment tree with index ver.
int Summa(int v, int lpos, int rpos, int left, int right, int ver)
{
if (left > right) return 0;
if ((lpos == left) && (rpos == right)) return SegTree[v][ver].sum;
int mid = (lpos + rpos) / 2;
Push(v, lpos, mid, rpos, ver);
return Summa(2 * v, lpos, mid, left, min(mid, right), ver) +
Summa(2 * v + 1, mid + 1, rpos, max(left, mid + 1), right, ver);
}Perform a push operation on all vertices of the segment tree with index ver. Then, insert the letter ver + 'a' into all positions of the string s where its value in the segment tree ver equals 1.
void get(int v, int lpos, int rpos, int ver)
{
if (SegTree[v][ver].sum == 0) return;
if (lpos == rpos)
{
s[lpos] = ver + 'a';
return;
}
int mid = (lpos + rpos) / 2;
Push(v, lpos, mid, rpos, ver);
get(2 * v, lpos, mid, ver);
get(2 * v + 1, mid + 1, rpos, ver);
}The main part of the program. Read the input data. Based on the input string s, build 26 segment trees — one for each letter of the Latin alphabet.
cin >> n >> q;
cin >> s;
s = " " + s;
build(1,1,n);
Process q queries sequentially.
for (i = 0; i < q; i++)
{
cin >> l >> r >> command;Perform a counting sort of all letters in the range [l;r]. To do this, first count the number of occurrences of each letter 'a' + j in this interval and store the result in cnt[j].
for (j = 0; j < ALPHABET; j++)
cnt[j] = Summa(1, 1, n, l, r, j);Then, starting from position pos, we'll move to the right or to the left depending on the value of the variable command.
pos = (command == 1) ? l : r;
for (j = 0; j < ALPHABET; j++)
{
if (!cnt[j]) continue;
SetValue(1, 1, n, l, r, 0, j);
if (command)
{
SetValue(1, 1, n, pos, pos + cnt[j] - 1, 1, j);
pos += cnt[j];
}
else
{
SetValue(1, 1, n, pos - cnt[j] + 1, pos, 1, j);
pos -= cnt[j];
}
}
}The generation of the resulting string is performed based on the contents of the segment trees. The function get(1,1,n,i), using the data from the i-th segment tree, places all letters 'a' + i at their corresponding positions in the string s. The get function performs a complete push, traversing all vertices of the segment tree in O(n) time.
for (i = 0; i < ALPHABET; i++)
get(1, 1, n, i);
Print the resulting string.