CodeForces 145 E. Lucky Queries(线段树)
E. Lucky Queries
Description:
Petya loves lucky numbers very much. Everybody knows that lucky numbers are positive integers whose decimal record contains only the lucky digits 4 and 7. For example, numbers 47, 744, 4 are lucky and 5, 17, 467 are not.
Petya brought home string s with the length of n. The string only consists of lucky digits. The digits are numbered from the left to the right starting with 1. Now Petya should execute m queries of the following form:
- switch l r — “switch” digits (i.e. replace them with their opposites) at all positions with indexes from l to r, inclusive: each digit 4 is replaced with 7 and each digit 7 is replaced with 4 (1 ≤ l ≤ r ≤ n);
- count — find and print on the screen the length of the longest non-decreasing subsequence of string s.
Subsequence of a string s is a string that can be obtained from s by removing zero or more of its elements. A string is called non-decreasing if each successive digit is not less than the previous one.
Help Petya process the requests.
Input:
The first line contains two integers n and m (1 ≤ n ≤ 106, 1 ≤ m ≤ 3·105) — the length of the string s and the number of queries correspondingly. The second line contains n lucky digits without spaces — Petya’s initial string. Next m lines contain queries in the form described in the statement.
Output
For each query count print an answer on a single line.
Sample Input:
2 3
47
count
switch 1 2
count
Sample Output:
2
1
Sample Input:
3 5
747
count
switch 1 1
count
switch 1 3
count
Sample Output:
2
3
2
题目链接
有一串只有 4 和 7 的数列,需要支持两种操作
switch l r
将区间 [l,r] 内的 4 变为 7 , 7 变为 4count
求整个数列的最长不下降子序列长度
看题目范围很容易想到线段树做法,其中对线段树每个节点四个属性:覆盖区间内 4 的数量、 7 的数量、最长不下降子序列长度、最长不上升子序列长度
其中进行区间更新时把 4、7 的数量互换,把最长不下降子序列长度、最长不上升子序列长度互换
而进行更新上传时时计算最长不下降子序列有三种情况
- 左子树最长不下降子序列长度+右子树 7 的数量
- 左子树 4 的数量+右子树最长不下降子序列长度
- 左子树 4 的数量+右子树 7 的数量
其中对三种情况取最大值即可,计算最长不上升子序列同理
AC代码:
#include <bits/stdc++.h>
using namespace std;
class seg_tree {
public:
typedef int type_t;
struct node {
type_t cnt4, cnt7, rise, fall, lazy;
node(type_t _cnt4 = 0, type_t _cnt7 = 0,
type_t _rise = 1, type_t _fall = 1,
type_t _lazy = 0): cnt4(_cnt4), cnt7(_cnt7),
rise(_rise), fall(_fall),
lazy(_lazy) {}
};
int n;
vector<node> tree;
node Unite(const node &k1, const node &k2) {
node ans;
ans.cnt4 = k1.cnt4 + k2.cnt4;
ans.cnt7 = k1.cnt7 + k2.cnt7;
ans.rise = max(k1.rise + k2.cnt7, max(k1.cnt4 + k2.cnt7, k1.cnt4 + k2.rise));
ans.fall = max(k1.fall + k2.cnt4, max(k1.cnt7 + k2.cnt4, k1.cnt7 + k2.fall));
return ans;
}
void Pull(int o) {
tree[o] = Unite(tree[o << 1], tree[o << 1 | 1]);
}
void Push(int o, int l, int r) {
if (tree[o].lazy != 0) {
swap(tree[o << 1].cnt4, tree[o << 1].cnt7);
swap(tree[o << 1].rise, tree[o << 1].fall);
swap(tree[o << 1 | 1].cnt4, tree[o << 1 | 1].cnt7);
swap(tree[o << 1 | 1].rise, tree[o << 1 | 1].fall);
tree[o << 1].lazy = !tree[o << 1].lazy;
tree[o << 1 | 1].lazy = !tree[o << 1 | 1].lazy;
tree[o].lazy = 0;
}
}
void Build(int o, int l, int r, const vector<type_t> &v) {
if (l == r) {
tree[o].cnt4 = (v[l - 1] == 4);
tree[o].cnt7 = (v[l - 1] == 7);
return;
}
int m = (l + r) >> 1;
Build(o << 1, l, m, v);
Build(o << 1 | 1, m + 1, r, v);
Pull(o);
}
seg_tree(const vector<type_t> &v) {
n = v.size();
tree.resize(n << 2);
Build(1, 1, n, v);
}
void Modify(int o, int l, int r, int ll, int rr) {
if (ll <= l && rr >= r) {
swap(tree[o].cnt4, tree[o].cnt7);
swap(tree[o].rise, tree[o].fall);
tree[o].lazy = !tree[o].lazy;
return;
}
Push(o, l, r);
int m = (l + r) >> 1;
if (ll <= m) Modify(o << 1, l, m, ll, rr);
if (rr > m) Modify(o << 1 | 1, m + 1, r, ll, rr);
Pull(o);
}
void Modify(int ll, int rr) {
Modify(1, 1, n, ll, rr);
}
};
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int n, m; cin >> n >> m;
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
char x; cin >> x;
arr[i] = x - '0';
}
seg_tree sgt(arr);
for (int i = 0, l, r; i < m; ++i) {
string s; cin >> s;
if (s == "count") cout << sgt.tree[1].rise << endl;
else {
cin >> l >> r;
sgt.Modify(l, r);
}
}
return 0;
}