每次找连续最长的序列(相等取左),并把它去掉。输出要做几次操作,变成空
POINT:
把每个连续的序列分号。从1 2 3标号。然后用链表连接。
全部放在优先队列里。
把最大的去掉之后。连接他的左边和右边。
判断他们能不能合并,可以的话,把他们从链表里删除,连接一个新值即他们两个的和,且他的l为左边的l。
给每个序列flag记录有么有被删了,被删了就不用ans++了。
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 500000+444;
int flag[maxn],a[maxn];
int num[maxn],pre[maxn],nxt[maxn];
struct node
{
int id,l;
int kind;
bool operator < (const node &a) const{
if(num[id]==num[a.id]){
return l>a.l;
}
return num[id]<num[a.id];
}
}b[maxn];
int cnt=0;
int main()
{
priority_queue<node> q;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
int x=0;
a[n+1]=-1;
for(int i=1;i<=n;i++){
x++;
if(a[i]!=a[i+1]){
++cnt;
b[cnt].id=cnt;
b[cnt].kind=a[i];
num[cnt]=x;
x=0;
}
}
for(int i=1;i<=cnt;i++){
b[i].l=i;
pre[i]=i-1;
nxt[i]=i+1;
q.push(b[i]);
}
nxt[cnt]=0;
int ans=0;
while(!q.empty()){
node now=q.top();
q.pop();
if(flag[now.id]) continue;
ans++;
int p=pre[now.id];
int nt=nxt[now.id];
if(p==0||nt==0||b[p].kind!=b[nt].kind){
nxt[p]=nt;
pre[nt]=p;
continue;
}
++cnt;
flag[p]=flag[nt]=1;
b[cnt].id=cnt;
b[cnt].kind=b[p].kind;
b[cnt].l=b[p].l;
num[cnt]=num[p]+num[nt];
q.push(b[cnt]);
nxt[pre[p]]=cnt;
pre[nxt[nt]]=cnt;
nxt[cnt]=nxt[nt];
pre[cnt]=pre[p];
}
printf("%d\n",ans);
return 0;
}