题目链接:http://codeforces.com/contest/650/problem/D
题意:
给你n个数,m个询问
每次单点修改,然后问你现在整个序列的lis长度。
修改完之后,要求修改回去。
解法:
询问离线。
我们维护四个东西,dp1[i]表示从1开始到第i个位置的最长上升子序列长度,dp2[i]表示从n开始到第i个位置的最长递减子序列长度。dp3[i]表示第i个询问的那个位置从1开始到第x(即询问的位置)个位置的最长上升子序列长度,dp4[i]表示递减。
假如询问是x,y那么
然后我们判断一下第x个位置是不是lis的关键位置,是的话,ans=lis。否则的话,ans=lis-1。关键位置就是这个位置是全局lis不可替代的一个数。
然后ans = max(ans,dp3[i]+dp4[i]-1)这个很显然……
然后就完了。
//CF 650D
#include <bits/stdc++.h>
using namespace std;
const int maxn = 400050;
int n, m, a[maxn], dp1[maxn], dp2[maxn], dp3[maxn], dp4[maxn];
///dp1[i]表示从1开始到第i个位置的最长上升子序列长度,dp2[i]表示从n开始到第i个位置的最长递减子序列长度。 ///dp3[i]表示第i个询问的那个位置从1开始到第x(即询问的位置)个位置的最长上升子序列长度,dp4[i]表示递减。
struct Seg{
struct node{
int l, r, maxlen;
}T[maxn*10];
void pushup(int rt){
T[rt].maxlen = max(T[rt*2].maxlen, T[rt*2+1].maxlen);
}
void build(int l, int r, int rt){
T[rt].l = l, T[rt].r = r, T[rt].maxlen = 0;
if(l == r) return;
int mid = (l+r)/2;
build(l, mid, rt*2);
build(mid+1, r, rt*2+1);
}
void update(int pos, int val, int rt){
if(T[rt].l == pos && pos == T[rt].r){
T[rt].maxlen = val;
return;
}
int mid = (T[rt].l + T[rt].r) / 2;
if(pos <= mid) update(pos, val, rt*2);
else update(pos, val, rt*2+1);
pushup(rt);
}
int query(int L, int R, int rt){
if(L <= T[rt].l && T[rt].r <= R){
return T[rt].maxlen;
}
else{
int mid = (T[rt].l + T[rt].r) / 2;
int res = 0;
if(L <= mid) res = max(res, query(L, R, rt*2));
if(mid < R) res = max(res, query(L, R, rt*2+1));
return res;
}
}
}L, R;
map <int, int> H;
vector <int> V;
struct node{
int x, y;
}Q[maxn];
vector <pair<int, int>> q[maxn]; //<idx, num>
int cnt[maxn];
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
V.push_back(a[i]);
}
for(int i = 1; i <= m; i++){
scanf("%d%d", &Q[i].x, &Q[i].y);
V.push_back(Q[i].y);
}
sort(V.begin(), V.end());
V.erase(unique(V.begin(), V.end()), V.end());
for(int i = 0; i < V.size(); i++) H[V[i]] = i+1;
for(int i = 1; i <= n; i++) a[i] = H[a[i]];
for(int i = 1; i <= m; i++){
Q[i].y = H[Q[i].y];
q[Q[i].x].push_back(make_pair(i, Q[i].y));
}
L.build(1, V.size()+5, 1);
for(int i = 1; i <= n; i++){
dp1[i] = L.query(1, a[i]-1, 1) + 1;
for(int j = 0; j < q[i].size(); j++){
int id = q[i][j].first;
int x = q[i][j].second;
dp3[id] = L.query(1, x-1, 1) + 1;
}
L.update(a[i], dp1[i], 1);
}
reverse(a+1, a+n+1);
R.build(1, V.size()+5, 1);
for(int i = 1; i <= n; i++){
dp2[i] = R.query(a[i]+1, V.size(), 1) + 1;
for(int j = 0; j < q[n-i+1].size(); j++){
int id = q[n-i+1][j].first;
int x = q[n-i+1][j].second;
dp4[id] = R.query(x+1, V.size(), 1) + 1;
}
R.update(a[i], dp2[i], 1);
}
int LIS = 0;
for(int i = 1; i <= n; i++){
LIS = max(LIS, dp1[i]);
}
for(int i = 1; i <= n; i++){
if(dp1[i] + dp2[n-i+1] == LIS + 1){
cnt[dp1[i]]++;
}
}
for(int i = 1; i <= m; i++){
int ans = LIS;
int x = Q[i].x;
if(dp1[x] + dp2[n-x+1] == LIS+1 && cnt[dp1[x]] == 1) ans--;
ans = max(ans, dp3[i] + dp4[i] - 1);
printf("%d\n", ans);
}
return 0;
}