Vasya has an array of integers of length n.
Vasya performs the following operations on the array: on each step he finds the longest segment of consecutive equal integers (the leftmost, if there are several such segments) and removes it. For example, if Vasya’s array is [13, 13, 7, 7, 7, 2, 2, 2], then after one operation it becomes [13, 13, 2, 2, 2].
Compute the number of operations Vasya should make until the array becomes empty, i.e. Vasya removes all elements from it.
The first line contains a single integer n (1 ≤ n ≤ 200 000) — the length of the array.
The second line contains a sequence a1, a2, …, an (1 ≤ ai ≤ 109) — Vasya’s array.
Print the number of operations Vasya should make to remove all elements from the array.
4
2 5 5 2
2
5
6 3 4 1 5
5
8
4 4 4 2 2 100 100 100
3
6
10 10 50 10 50 50
4
题面不难,给你一个序列,每次把其中最左边连续相等的数字去除,问最多需要多少次可以将整个序列全部除去。开始一直都是用set存每个线段的起点,终点和长度,但是每次在删除和合并的时候不知道如何处理线段的长度问题。看了题解之后,才发现,我们可以有两种方式储存线段,一是起点加终点,二是起点加长度。在这道题中,我们在删除一个线段后,就不是很容易算出合并之后的线段长度,用起点加长度就可以避免这个问题。
代码如下:
#include
using namespace std;
const int maxn = 2e5 + 6;
int n;
int a[maxn];
setint , int> >s1, s2;
int main()
{
ios::sync_with_stdio(false);
cin >> n;
int l, r;
for(l = 1, r = 1; r <= n; r++) {
cin >> a[r];
if(a[r] != a[l]) {
s1.insert({l - r, l});
s2.insert({l, r - l});
l = r;
}
}
s1.insert({l - r, l});
s2.insert({l, r - l});
int cnt = 0;
while(s1.size() > 1) {
cnt++;
pair<int, int> temp = *s1.begin();
s1.erase(temp);
int st = temp.second;
int len = -temp.first;
auto lpos = s2.lower_bound({st, len});
auto rpos = s2.upper_bound({st, len});
if(lpos == s2.begin() || rpos == s2.end()) {
s2.erase({st, len});
continue;
}
lpos--;
if(a[lpos->first] == a[rpos->first]) {
int st1 = lpos->first, st2 = rpos->first;
int len1 = lpos->second, len2 = rpos->second;
s1.erase({ -len1, st1});
s1.erase({ -len2, st2});
s2.erase({st1, len1}), s2.erase({st2, len2});
s1.insert({ -len1 - len2, st1});
s2.insert({st1, len1 + len2});
}
s2.erase({st, len});
}
cnt++;
cout << cnt << endl;
return 0;
}