【YBTOJ】【CodeForces 558E】A Simple Task
链接:
题目大意:
对一个字符串区间升降排序。
正文:
本题与 【Luogu P2824】[HEOI2016/TJOI2016]排序 有异曲同工之妙。这种升降排序的问题,可以通过维护每个字符在某位置是否有值,通过区间修改区间求和可以改变位置。
比如字符串 \(s=\{\texttt{a,e,c,c,d}\}\),若我们要升序排序 \([2,4]\),且已经求到字符 \(\texttt{c}\)。那么在 \(c\) 的线段树中可以看作是:\(t_\texttt{c}=\{0,0,1,1,0\}\)。接着是步骤:
- 求出 \([2,4]\) 中有多少个字符 \(\texttt{c}\),可以通过区间求和实现得到 \(3\)。
- 将 \([2,4]\) 中所有 \(\texttt{c}\) 清空,得到 \(t_\texttt{c}=\{0,0,0,0,0\}\)。
- 接着求出 \(\texttt{c}\) 应在的位置 \([2,3]\),并区间修改得到 \(t_\texttt{c}=\{0,1,1,0,0\}\)
所以可以维护二十六棵线段树实现。
代码:
const int N = 1e5 + 10;
inline ll Read()
{
ll x = 0, f = 1;
char c = getchar();
while (c != '-' && (c < '0' || c > '9')) c = getchar();
if (c == '-') f = -f, c = getchar();
while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
return x * f;
}
int n, m;
char a[N];
struct SegmentTree
{
struct Tree
{
int l, r, val, lzy;
}t[27][N << 3];
void Build(int l, int r, int p)
{
for (int i = 1; i <= 26; i++)
t[i][p].l = l, t[i][p].r = r, t[i][p].lzy = -1, t[i][p].val = 0;
if (l == r)
{
t[a[l] - 'a' + 1][p].val = 1;
return;
}
int mid = l + r >> 1;
Build(l, mid, p << 1),
Build(mid + 1, r, p << 1 | 1);
for (int i = 1; i <= 26; i++)
t[i][p].val = t[i][p << 1].val + t[i][p << 1 | 1].val;
}
void Spread(int p, int col)
{
if (~t[col][p].lzy)
{
t[col][p << 1].val = t[col][p].lzy * (t[col][p << 1].r - t[col][p << 1].l + 1);
t[col][p << 1].lzy = t[col][p].lzy;
t[col][p << 1 | 1].val = t[col][p].lzy * (t[col][p << 1 | 1].r - t[col][p << 1 | 1].l + 1);
t[col][p << 1 | 1].lzy = t[col][p].lzy;
t[col][p].lzy = -1;
}
}
void Modify(int l, int r, int p, int val, int col)
{
if (l <= t[col][p].l && t[col][p].r <= r)
{
t[col][p].val = val * (t[col][p].r - t[col][p].l + 1);
t[col][p].lzy = val;
return ;
}
Spread(p, col);
int mid = t[col][p].l + t[col][p].r >> 1;
if (l <= mid) Modify(l, r, p << 1, val, col);
if (mid < r) Modify(l, r, p << 1 | 1, val, col);
t[col][p].val = t[col][p << 1].val + t[col][p << 1 | 1].val;
}
int Query(int l, int r, int p, int col)
{
if (l <= t[col][p].l && t[col][p].r <= r) return t[col][p].val;
Spread(p, col);
int mid = t[col][p].l + t[col][p].r >> 1, ans = 0;
if (l <= mid) ans += Query(l, r, p << 1, col);
if (mid < r) ans += Query(l, r, p << 1 | 1, col);
return ans;
}
void Print(int p)
{
if(t[1][p].l == t[1][p].r)
{
for (int i = 1; i <= 26; i++)
if (t[i][p].val)
{
printf("%c", i - 1 + 'a');
return;
}
}
for (int i = 1; i <= 26; i++)
Spread(p, i);
Print(p << 1), Print(p << 1 | 1);
}
}t;
int main()
{
n = Read(), m = Read();
scanf ("%s", a + 1);
t.Build(1, n, 1);
for (int op, l, r; m--; )
{
l = Read(), r = Read(), op = Read();
int L = l;
for (int i = op? 1: 26; op? i <= 26: i; op? i++: i--)
{
int cnt = t.Query(l, r, 1, i);
if (!cnt) continue;
t.Modify(l, r, 1, 0, i);
t.Modify(L, L + cnt - 1, 1, 1, i);
L += cnt;
}
}
t.Print(1);
return 0;
}