codeforces 558E A Simple Task 线段树

题目链接

题意较为简单。

思路:

由于仅仅有26个字母,所以用26棵线段树维护就好了,比較easy。

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <cstdio>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
using namespace std;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != ‘-‘ && (c<‘0‘ || c>‘9‘)) c = getchar();
	sgn = (c == ‘-‘) ? -1 : 1;
	ret = (c == ‘-‘) ? 0 : (c - ‘0‘);
	while (c = getchar(), c >= ‘0‘&&c <= ‘9‘) ret = ret * 10 + (c - ‘0‘);
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar(‘-‘);
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + ‘0‘);
}
typedef long long ll;
typedef pair<ll, ll> pii;
const int N = 1e5 + 100;
#define lson (id<<1)
#define rson (id<<1|1)
#define L(x) tree[x].l
#define R(x) tree[x].r
#define Hav(x) tree[x].hav
#define Siz(x) tree[x].siz
#define Lazy(x) tree[x].lazy
struct Tree {
	struct Node {
		int l, r, siz;//siz表示区间长度
		int hav;//hav表示这个区间的和
		int lazy;//lazy为2表示清空区间 lazy为1表示把区间都变为1
	}tree[N << 2];
	void build(int l, int r, int id) {
		L(id) = l; R(id) = r; Siz(id) = r - l + 1;
		Hav(id) = Lazy(id) = 0;
		if (l == r)return;
		int mid = (l + r) >> 1;
		build(l, mid, lson); build(mid + 1, r, rson);
	}
	void Down(int id) {
		if (Lazy(id) == 1) {
			Lazy(id) = 0;
			Hav(lson) = Siz(lson); Hav(rson) = Siz(rson);
			Lazy(lson) = Lazy(rson) = 1;
		}
		else if (Lazy(id) == 2) {
			Lazy(id) = 0;
			Hav(lson) = Hav(rson) = 0;
			Lazy(lson) = Lazy(rson) = 2;
		}
	}
	void Up(int id) {
		Hav(id) = Hav(lson) + Hav(rson);
	}
	void updata(int l, int r, int val, int id) {
		if (l == L(id) && R(id) == r) {
			if (val == 1)
				Hav(id) = Siz(id);
			else Hav(id) = 0;
			Lazy(id) = val;
			return;
		}
		Down(id);
		int mid = (L(id) + R(id)) >> 1;
		if (r <= mid)updata(l, r, val, lson);
		else if (mid < l)updata(l, r, val, rson);
		else {
			updata(l, mid, val, lson);
			updata(mid + 1, r, val, rson);
		}
		Up(id);
	}
	int query(int l, int r, int id) {
		if (l == L(id) && R(id) == r) {
			return Hav(id);
		}
		Down(id);
		int mid = (L(id) + R(id)) >> 1, ans = 0;
		if (r <= mid)ans = query(l, r, lson);
		else if (mid < l)ans = query(l, r, rson);
		else {
			ans = query(l, mid, lson) + query(mid + 1, r, rson);
		}
		Up(id);
		return ans;
	}
};
Tree alph[26];
int n, q;
char s[N];
int sum[26];
int main() {
	rd(n); rd(q);
	for (int i = 0; i < 26; i++)alph[i].build(1, n, 1);
	scanf("%s", s + 1);
	for (int i = 1; i <= n; i++) {
		alph[s[i] - ‘a‘].updata(i, i, 1, 1);
	}
	while (q--) {
		int l, r, in;
		rd(l); rd(r); rd(in);
		memset(sum, 0, sizeof sum);
		for (int i = 0; i < 26; i++)
		{
			sum[i] += alph[i].query(l, r, 1);
			alph[i].updata(l, r, 2, 1);
		}
		int tim = 26, i;
		if (in)i = 0; else i = 25, in = -1;
		for (;tim--; i += in) {
			if (sum[i] == 0)continue;
			alph[i].updata(l, l + sum[i] - 1, 1, 1);
			l += sum[i];
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 26; j++)
			if (alph[j].query(i, i, 1))
			{
				putchar(j + ‘a‘); break;
			}
	}
	return 0;
}
时间: 2025-01-05 16:25:55

codeforces 558E A Simple Task 线段树的相关文章

计数排序 + 线段树优化 --- Codeforces 558E : A Simple Task

E. A Simple Task Problem's Link: http://codeforces.com/problemset/problem/558/E Mean: 给定一个字符串,有q次操作,每次操作将(l,r)内的字符升序或降序排列,输出q次操作后的字符串. analyse: 基本思想是计数排序. 所谓计数排序,是对一个元素分布较集中的数字集群进行排序的算法,时间复杂度为O(n),但使用条件很苛刻.首先对n个数扫一遍,映射出每个数字出现的次数,然后再O(n)扫一遍处理出:对于数字ai,

Codeforces 558E A Simple Task (计数排序&amp;&amp;线段树优化)

题目链接:http://codeforces.com/contest/558/problem/E E. A Simple Task time limit per test5 seconds memory limit per test512 megabytes inputstandard input outputstandard output This task is very simple. Given a string S of length n and q queries each quer

[线段树] codeforces 558E. A Simple Task

题意: 给一个长度n的字符串,q次操作,每次操作把[l,r]排序,k=0非递增,k=1非递减. 题解: 采用计数排序的复杂度是O(n?q),无法通过,但有所启示. 可以看出计数就是区间求和,排序就是区间更新,可以用线段树维护. 做法是建立26棵线段树,第i棵树维护第i个字母的位置信息. 计数时,在26棵线段树内分别做一次查询,排序时根据递增还是递减,把相应的区间赋值为相应的字母. #include<bits/stdc++.h> #define lson rt<<1,l,mid #d

Codeforces 558E A Simple Task

Discription This task is very simple. Given a string S of length n and q queries each query is on the format i j k which means sort the substring consisting of the characters from i to j in non-decreasing order if k?=?1 or in non-increasing order if 

CF558E - A Simple Task线段树

给出一个小写字母组成的字符串,然后q个操作,a,b,c ,c为0 ,将区间 [a,b] 按逆字典序排,c为1,将此区间按字典序排.用一颗线段树,维护每个节点各个字母出现的种类数,每次操作操作后,暴力将字母a组成的区间,字母b组成的区间等等,区间内所有元素更新为a,b,等等.打个lazy标记,区间更新搞下就行了. #pragma comment(linker,"/STACK:102400000,102400000") #define _CRT_SECURE_NO_WARNINGS #in

CF558E A Simple Task 线段树

题意翻译 题目大意: 给定一个长度不超过10^5的字符串(小写英文字母),和不超过50000个操作. 每个操作 L R K 表示给区间[L,R]的字符串排序,K=1为升序,K=0为降序. 最后输出最终的字符串. 给每个数字开一个线段树    如果该数字在pos位置  那么在该数字的线段树的pos 位置+1  (有一点类似权值线段树) 因为一个点不是0就是1  (不可能有两个数字在一个点)开绝对标记即可 每次操作的时候  如果是递增的从小到大遍历数字的线段树即可  每次先找出区间个数  放在最左边

Codeforces 444C DZY Loves Colors(线段树)

题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是修改区间上l到r上面德值为x,2是询问l到r区间总的修改值. 解题思路:线段树模板题. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 5*1e5; typedef long lo

Codeforces 57B Martian Architecture 暴力||线段树

题目链接:点击打开链接 题意:n长的序列(初始全为0) m个操作 k个查询 下面m个操作[l,r] h 代表 a[l] +=h; a[l+1] += h+i; a[l+i] += h+i;  l<=i<=r 然后问k个位置的和 因为k<=100 所以直接暴力也可以 ----------------------- 如果k<=100000 也是可以做的 只需要给区间记录一个标记lazy,表示从左端点开始 l, l+1, l+i ··· l+r 而向下更新时, 左区间则直接更新, 右区间

Codeforces GYM 100114 D. Selection 线段树维护DP

D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Description When selecting files in an application dialog, Vasya noted that he can get the same selection in different ways. A simple mouse click selects a sing