• 【YBTOJ】【CodeForces 558E】A Simple Task


    链接:

    洛谷

    题目大意:

    对一个字符串区间升降排序。

    正文:

    本题与 【Luogu P2824】[HEOI2016/TJOI2016]排序 有异曲同工之妙。这种升降排序的问题,可以通过维护每个字符在某位置是否有值,通过区间修改区间求和可以改变位置。

    比如字符串 (s={ exttt{a,e,c,c,d}}),若我们要升序排序 ([2,4]),且已经求到字符 ( exttt{c})。那么在 (c) 的线段树中可以看作是:(t_ exttt{c}={0,0,1,1,0})。接着是步骤:

    1. 求出 ([2,4]) 中有多少个字符 ( exttt{c}),可以通过区间求和实现得到 (3)
    2. ([2,4]) 中所有 ( exttt{c}) 清空,得到 (t_ exttt{c}={0,0,0,0,0})
    3. 接着求出 ( exttt{c}) 应在的位置 ([2,3]),并区间修改得到 (t_ exttt{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;
    }
    
    
  • 相关阅读:
    VMWare相关知识
    QTP中的DataTable操作
    解决Access的sql语句join两次出错的问题
    .net环境用GDI+绘制倾斜文字
    用JS读取XML文件
    再认识asp.net的postback机制:探索__doPostBack的来龙去脉
    用Jquery读取Json内容
    JS取URL参数值的一个方法
    WinForm在窗体里面添加窗体
    ASP.NET2.0Theme回顾总结
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14878891.html
Copyright © 2020-2023  润新知