1. 程式人生 > 其它 >【YBTOJ】【CodeForces 558E】A Simple Task

【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;
}