思路:
队列维护可能发生的突变点。
双向链表维护序列位置转移。
附送一题:HDU6058
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int Maxn = 1e5 + 10;
int pre[Maxn], nex[Maxn];
int a[Maxn], n;
int ans[Maxn], num;
queue<int>q;
bool vis[Maxn];
bool in[Maxn];
void Clear(int x){
vis[x] = true;
pre[nex[x]] = pre[x];
nex[pre[x]] = nex[x];
}
void solve(){
for(int i=1;i<=n;i++){
pre[i] = i - 1;
nex[i] = i + 1;
}
pre[n+1] = n;
nex[0] = 1;
bool flag = false;
int tmp = n, Right, pos;
for(int i=n;i>=1;i--){
q.push(i);
vis[i] = false;
in[i] = true;
}
while(!q.empty()){
Right = q.front();q.pop();in[Right] = false;
if(vis[Right]) continue;
pos = Right;
if(pre[pos]>=1 && a[pos] < a[pre[pos]]){
if(nex[pos] <= n && !in[nex[pos]])
q.push(nex[pos]), in[nex[pos]] = true;
while(pre[pos] >= 1 && a[pos] < a[pre[pos]]){
Clear(pos);
pos = pre[pos];
}
if(pos >= 1) Clear(pos);
}
}
num = 0;
for(int i=1;i<=n;++i)
if(!vis[i]) ans[++num] = a[i];
printf("%d\n", num);
for(int i=1;i<=num;i++) printf("%d ", ans[i]);
puts("");
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i=1;i<=n;i++) scanf("%d", &a[i]);
if(n == 1){
puts("1");
printf("%d\n", a[1]);
continue;
}
solve();
}
return 0;
}