題目鏈接:點擊這裏
題意:給出一個序列,從頭到尾依次扔進一個雙端隊列或者直接不要,雙端隊列可以在任意時刻從頭或者尾彈出元素。最大化最後的雙端隊列size。
求出每個下標開頭的最長遞增序列和最長遞減序列,然後掃一遍用樹狀數組維護即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
using namespace std;
#define maxn 100005
int dp[maxn], dp2[maxn];//以i開頭的最長遞增子序列 以i開頭的最長遞減子序列
int c[maxn], a[maxn], n;
vector <int> num;
int gg[maxn], cnt;
void lisanhua () {//離散化
sort (num.begin (), num.end ());
for (int i = 0; i < n; i++) {
if (!i || num[i] != num[i-1]) {
gg[++cnt] = num[i];
}
}
for (int i = 1; i <= n; i++) {
a[i] = lower_bound (gg+1, gg+1+cnt, a[i])-gg;
}
}
int lowbit (int x) {
return x&(-x);
}
void update1 (int pos, int num) {
for (int i = pos; i > 0; i -= lowbit (i))
c[i] = max (c[i], num);
}
void update2 (int pos, int num) {
for (int i = pos; i <= n; i += lowbit (i))
c[i] = max (c[i], num);
}
int query_max (int pos) {
int ans = 0;
for (int i = pos; i <= n; i += lowbit (i)) {
ans = max (ans, c[i]);
}
return ans;
}
int query_min (int pos) {
int ans = 0;
for (int i = pos; i > 0; i -= lowbit (i)) {
ans = max (ans, c[i]);
}
return ans;
}
void solve () {
memset (c, 0, sizeof c);
for (int i = n; i >= 1; i--) {
dp[i] = query_max (a[i])+1;
update1 (a[i], dp[i]);
}
memset (c, 0, sizeof c);
for (int i = n; i >= 1; i--) {
dp2[i] = query_min (a[i])+1;
update2 (a[i], dp2[i]);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
int tmp = query_min (a[i]-1);
ans = max (ans, tmp+dp[i]);
}
printf ("%d\n", ans);
}
int main () {
//freopen ("more.in", "r", stdin);
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d", &n);
cnt = 0;
num.clear ();
for (int i = 1; i <= n; i++) {
scanf ("%d", &a[i]);
num.push_back (a[i]);
}
lisanhua ();
solve ();
}
return 0;
}