版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HuangXinyue1017/article/details/83471835
Time Limits: 4000 ms Memory Limits: 524288 KB
Description
当一阵风吹来,风筝飞上天空,为了你,而祈祷,而祝福,而感动……
oyiya 在 AK 了 IOI 之后来到了乡下,在田野中玩耍,放松身心。
他发现前面有一排小朋友在放风筝,每一个风筝有一个高度 hi,风筝的高度可能会随着小朋友的心情而改变。这时,毒瘤的 oyiya 有了一个毒瘤的 idea,他想知道改变高度之后风筝的最长严格上升子序列。oyiya 太强了表示并不想做这种水题,你能解决这个问题吗?
Input
第一行为两个整数 n, m,表示小朋友的个数和询问数。
第二行有 n 个整数,表示 hi。
接下来 m 行,每行两个整数 ai, bi,表示询问将第 ai 只风筝的高度变成 bi 后的 LIS。注意询问之间是独立的,后面的询问不受前面询问的影响.
Output
m 行,每行一个整数表示询问的答案。
Sample Input
3 3
2 2 3
1 3
1 1
3 2
Sample Output
2
3
1
Data Constraint
Solution
- 题目要我们动态求出序列的LIS
- 记原序列的LIS长度为
- 不难发现答案只有三种可能:
- 对于每次修改操作 ,我们将 挂在 位置上
- 在求 (长度为 的最长严格递增子序列的末尾最小值)的时候顺便将询问拿出来
- 求出若以它结尾从前往后最长长度 ,以及从后往前最长长度
- 我们考虑新序列的 的情况,它对于这个 可以选或不选
- 对于必选情况,显然
- 对于不选情况
- 如果它出现在原序列的最长严格递增子序列中而且最长严格递增子序列只有必选它这一个,那么
- 否则有别的位置可以使最长严格递增子序列长度仍为 ,所以
- 如果它没有出现在原序列的最长严格递增子序列中,那么
- 最终将几种情况的答案取个 就好啦
Code
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int N=5e5+5;
int n,m,t,lis;
int a[N],z[N],c[N],L[N],R[N],ans[N];
bool no[N];
struct node{int x,id;};
vector<node> V[N];
vector<int>Rank1[N],Rank2[N];
int main()
{
freopen("kite.in","r",stdin);
freopen("kite.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
V[x].push_back((node){y,i});
}
t=0,memset(z,0,sizeof(z));
fo(i,1,n)
{
if(V[i].size())
{
fo(j,0,V[i].size()-1)
{
int Rank=lower_bound(z+1,z+1+t,V[i][j].x)-z;
Rank1[i].push_back(Rank);
}
}
if(!t) z[++t]=a[i],L[i]=1;
else
{
int x=lower_bound(z+1,z+1+t,a[i])-z;
z[x]=a[i],t=max(t,x),L[i]=x;
}
}
lis=t;
t=0,memset(z,0,sizeof(z));
fd(i,n,1)
{
if(V[i].size())
{
fo(j,0,V[i].size()-1)
{
int Rank=lower_bound(z+1,z+1+t,-V[i][j].x)-z;
Rank2[i].push_back(Rank);
}
}
if(!t) z[++t]=-a[i],R[i]=1;
else
{
int x=lower_bound(z+1,z+1+t,-a[i])-z;
z[x]=-a[i],t=max(t,x),R[i]=x;
}
}
fo(i,1,n) if(L[i]+R[i]-1==lis) ++c[L[i]];
fo(i,1,n) if(L[i]+R[i]-1==lis&&c[L[i]]>1) no[i]=1;
fo(i,1,n) if(V[i].size())
fo(j,0,V[i].size()-1)
{
int p=0;
if(L[i]+R[i]-1==lis&&no[i]||L[i]+R[i]-1!=lis) p=lis; else p=lis-1;
p=max(p,Rank1[i][j]+Rank2[i][j]-1);
ans[V[i][j].id]=p;
}
fo(i,1,m) printf("%d\n",ans[i]);
}