Luogu 2787 語文1(chin1)- 理理思維
阿新 • • 發佈:2018-12-15
題目連結:傳送門
題目背景
蒟蒻HansBug在語文考場上,撓了無數次的頭,可腦子裡還是一片空白。
題目描述
考試開始了,可是蒟蒻HansBug腦中還是一片空白。哦不!準確的說是亂七八糟的。現在首要任務就是幫蒟蒻HansBug理理思維。假設HansBug的思維是一長串字串(字串中包含且僅包含26個字母),現在的你,有一張神奇的藥方,上面依次包含了三種操作:
獲取第x到第y個字元中字母k出現了多少次
將第x到第y個字元全部賦值為字母k
將第x到第y個字元按照A-Z的順序排序
你欣喜若狂之時,可是他腦細胞和RP已經因為之前過度緊張消耗殆盡,眼看試卷最後還有一篇800字的作文呢,所以這個關鍵的任務就交給你啦!
輸入格式:
第一行包含兩個整數N、M,分別表示HansBug的思維所包含的字母個數和藥方上操作個數。
第二行包含一個長度為N的字串,表示HansBug的思維。
第3-M+2行每行包含一條操作,三種操作格式如下:
操作1: 1 xi yi ki 表示將第xi到第yi個字元中ki出現的次數輸出
操作2: 2 xi yi ki 表示將第xi到第yi個字元全部替換為ki
操作3: 3 xi yi 表示將第xi到第yi個字元按照A-Z的順序排序
輸出格式:
輸出為若干行,每行包含一個整數,依次為所有操作1所得的結果。
輸入樣例
10 5
ABCDABCDCD
1 1 3 A
3 1 5
1 1 3 A
2 1 2 B
1 2 3 B
輸出樣例
1
2
2
說明
樣例說明:
資料規模:
此題目中大小寫不敏感。
這也是珂朵莉樹的好題
正常珂朵莉樹開O2之後跑到400ms左右是沒問題的
空間複雜度也在4MB左右
線段樹的話2000ms和幾十MB是很普遍的
優勢又體現出來了(~ ̄▽ ̄)~
具體怎麼寫在程式碼裡說
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <complex>
#include <algorithm>
#include <climits>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define A 50010
#define B 2010
#define ll long long
#define iter set<node>::iterator
using namespace std;
struct node {
int l, r;
mutable char v;
node (int L, int R = -1, char V = -1) : l(L), r(R), v(V){}
bool operator < (const node &a) const{
return l < a.l;
}
};
set<node> s;
int n, m, cnt[27];
int opt, x, y;
iter split(int pos) {
iter it = s.lower_bound(node(pos));
if (it != s.end() and it->l == pos) return it;
it--;
int lcc = it->l, rcc = it->r;
char val = it->v;
s.erase(it);
s.insert(node(lcc, pos - 1, val));
return s.insert(node(pos, rcc, val)).first;
}
void assign(int l, int r, char val) {
iter rcc = split(r + 1), lcc = split(l);
s.erase(lcc, rcc);
s.insert(node(l, r, val));
}
int asksum(int l, int r, char ds) { //查詢區間內指定字母的個數
iter rcc = split(r + 1), lcc = split(l);
int ans = 0;
for (; lcc != rcc; lcc++)
if (lcc->v == ds)
ans += lcc->r - lcc->l + 1;
return ans;
}
void sor(int l, int r) {
iter rcc = split(r + 1), lcc = split(l); //記下每個字母有多少個
for (iter it = lcc; it != rcc; it++) cnt[it->v - 'A'] += it->r - it->l + 1;
s.erase(lcc, rcc); int pos = l;
for (int i = 0; i < 26; i++)
if (cnt[i]) {
s.insert(node(pos, pos + cnt[i] - 1, i + 'A')); //按順序插進去
pos += cnt[i]; //移位,繼續往後放
cnt[i] = 0; //放到最後清也可以
}
}
char ss[A], c[2];
int main() {
scanf("%d%d", &n, &m);
scanf("%s", ss + 1);
for (int i = 1; i <= n; i++) ss[i] = toupper(ss[i]); //記得都轉成大寫的
for (int i = 1; i <= n; i++) s.insert(node(i, i, ss[i])); //初始化的字母都塞進去
while (m--) {
scanf("%d%d%d", &opt, &x, &y);
if (opt != 3) scanf("%s", c + 1), c[1] = toupper(c[1]);
if (opt == 1) printf("%d\n", asksum(x, y, c[1]));
if (opt == 2) assign(x, y, c[1]);
if (opt == 3) sor(x, y);
}
return 0;
}