【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\}\)。接着是步骤:

  1. 求出 \([2,4]\) 中有多少个字符 \(\texttt{c}\),可以通过区间求和实现得到 \(3\)
  2. \([2,4]\) 中所有 \(\texttt{c}\) 清空,得到 \(t_\texttt{c}=\{0,0,0,0,0\}\)
  3. 接着求出 \(\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;
}

posted @ 2021-06-12 20:11  Jayun  阅读(41)  评论(0编辑  收藏  举报