Codeforces Round #345 (Div. 1) D. Zip-line

D. Zip-line
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Vasya has decided to build a zip-line on trees of a nearby forest. He wants the line to be as long as possible but he doesn't remember exactly the heights of all trees in the forest. He is sure that he remembers correct heights of all trees except, possibly, one of them.

It is known that the forest consists of n trees staying in a row numbered from left to right with integers from 1 to n. According to Vasya, the height of the i-th tree is equal to hi. The zip-line of length k should hang over k (1 ≤ k ≤ n) trees i1, i2, ..., ik (i1 < i2 < ... < ik) such that their heights form an increasing sequence, that is hi1 < hi2 < ... < hik.

Petya had been in this forest together with Vasya, and he now has q assumptions about the mistake in Vasya's sequence h. His i-th assumption consists of two integers ai and bi indicating that, according to Petya, the height of the tree numbered ai is actually equal to bi. Note that Petya's assumptions are independent from each other.

Your task is to find the maximum length of a zip-line that can be built over the trees under each of the q assumptions.

In this problem the length of a zip line is considered equal to the number of trees that form this zip-line.

Input

The first line of the input contains two integers n and m (1 ≤ n, m ≤ 400 000) — the number of the trees in the forest and the number of Petya's assumptions, respectively.

The following line contains n integers hi (1 ≤ hi ≤ 109) — the heights of trees according to Vasya.

Each of the following m lines contains two integers ai and bi (1 ≤ ai ≤ n1 ≤ bi ≤ 109).

Output

For each of the Petya's assumptions output one integer, indicating the maximum length of a zip-line that can be built under this assumption.

Examples
input
4 4
1 2 3 4
1 1
1 4
4 3
4 5
output
4
3
3
4
input
4 2
1 3 2 6
3 5
2 4
output
4
3
Note

Consider the first sample. The first assumption actually coincides with the height remembered by Vasya. In the second assumption the heights of the trees are (4, 2, 3, 4), in the third one they are (1, 2, 3, 3) and in the fourth one they are (1, 2, 3, 5).

给你一个初始的序列,q个操作,每个操作把x位置的数改成y,每一个操作之后输出当前的最长上升子序列(修改不累加)

 

思路:当一个位置修改后,他有可能出现以下三种情况

1.成为一个新的最长上升子序列

2.原来这个位置的数是一个关键位置,那么这时候的答案便有可能是原来的LIS-1或者原来的LIS

3.原来的数不是一个关键位置,那么最长上升子序列长度不变

 

判断是否是关键上升子序列的方法:

到这个点结束的最长上升子序列+从这个点开始的最长上升子序列(不包括这个点)是否等于最长上升子序列

且到这个点结束的最长上升子序列的长度只有一个(表达不好,具体见程序)

#include<bits/stdc++.h>
using namespace std;
const int maxn=400100;
int l[maxn],r[maxn];
int a[maxn],b[maxn],ans[maxn],line[maxn];
struct node{
    int x,y,id;
}Q[maxn];

int DP1(int n,int q){
    int i,len,pos;
    b[1]=a[1];
    l[1]=1,len=1;
    int tot=1;
    while(Q[tot].x==1&&tot<=q){
        ans[Q[tot].id]=1;
        tot++;
    }
    for(int i=2;i<=n;i++){
        while(Q[tot].x==i&&tot<=q){
            pos=lower_bound(b+1,b+len+1,Q[tot].y)-b;
            ans[Q[tot].id]=pos;
            tot++;
        }
        if(a[i]>b[len])
            len=len+1,l[i]=len,b[len]=a[i];
        else{
            pos=lower_bound(b+1,b+len+1,a[i])-b;;
            b[pos]=a[i],l[i]=pos;
        }
    }
    return len;
}

int search(int num,int low,int high){
    while(high-low>=0){
        int mid=(low+high)>>1;
        if(b[mid]<=num)
            high=mid-1;
        else
            low=mid+1;
    }
    return low;
}

void DP2(int n,int q){
    int i,len,pos;
    b[1]=a[n];
    r[n]=0,len=1;
    int tot=q;
    while(Q[tot].x==n&&tot>=1)
        tot--;
    for(int i=n-1;i>=1;i--){
        while(Q[tot].x==i&&tot>=1){
            ans[Q[tot].id]+=search(Q[tot].y,1,len)-1;
            tot--;
        }
        if(a[i]<b[len])
            len=len+1,r[i]=len-1,b[len]=a[i];
        else{
            pos=search(a[i],1,len);
            b[pos]=a[i],r[i]=pos-1;
        }
    }
}

int C[maxn],ok[maxn];
bool cmp(node x,node y){
    return x.x<y.x;
}

int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=q;i++){
        scanf("%d%d",&Q[i].x,&Q[i].y);
        Q[i].id=i,line[i]=Q[i].x;
    }
    sort(Q+1,Q+q+1,cmp);
    int LISLEN=DP1(n,q);
    DP2(n,q);
    for(int i=1;i<=n;i++){
        if(l[i]+r[i]!=LISLEN)
            continue;
        C[l[i]]++;
    }
    for(int i=1;i<=n;i++){
        if(l[i]+r[i]!=LISLEN)
            continue;
        ok[i]=(C[l[i]]==1);
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",max(ans[i],LISLEN-ok[line[i]]));
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值