题意:
给一个长度为n的序列,m次询问,给定区间[a,b],你的任务是从[a,b]中选择一个点,使得从这个点出发走到b的贪心上升子序列最长,输出最长的序列长度。贪心上升子序列指的是每遇到一个值比当前队尾的值大就加入队列(不同于最长上升子序列)。
题解:
先考虑对于a[i],它会影响那些位置的答案。
显然,对于a[i],会对从(las[i]+1)~i的位置出发的答案造成1的贡献(las[i]为上一个大于等于a[i]的位置)。因为从这些点出发,无论怎么走,都是会走到i的,因此答案会+1。
由于本题数据较大,因此我们可以离线,按照右端点排序,每次加入一个i,就把(las[i]+1)~i的位置全部+1。求答案只需要找到[a,b]中的最大值即可。用线段树维护即可解决上述操作与查询。
#include<cstdio> #include<algorithm> #include<cstdlib> using namespace std; int n,m,a[1500002],ans[1500002],t[1500002],len,c[1500002]; typedef struct{ int l,r,num; }P; typedef struct{ int Max,f; }PP; P p[1500002]; PP xds[6000002]; int read(){ int f=0;char ch=getchar(); while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){f=f*10+ch-48;ch=getchar();} return f; } bool cmp(P aa,P bb){ return (aa.r<bb.r); } void pushdown(int root){ if (xds[root].f) { xds[root*2].Max+=xds[root].f;xds[root*2+1].Max+=xds[root].f; xds[root*2].f+=xds[root].f;xds[root*2+1].f+=xds[root].f; xds[root].f=0; } } void gengxin(int root,int begin,int end,int begin2,int end2){ if (begin>end2 || end<begin2)return; if (begin>=begin2 && end<=end2) { xds[root].Max++;xds[root].f++; return; } int mid=(begin+end)/2;pushdown(root); gengxin(root*2,begin,mid,begin2,end2);gengxin(root*2+1,mid+1,end,begin2,end2); xds[root].Max=max(xds[root*2].Max,xds[root*2+1].Max); } int chaxun(int root,int begin,int end,int begin2,int end2){ if (begin>end2 || end<begin2)return 0; if (begin>=begin2 && end<=end2)return xds[root].Max; int mid=(begin+end)/2;pushdown(root); return max(chaxun(root*2,begin,mid,begin2,end2),chaxun(root*2+1,mid+1,end,begin2,end2)); } int main() { n=read();m=read(); for (int i=1;i<=n;i++)a[i]=read(); for (int i=1;i<=m;i++) { p[i].l=read();p[i].r=read();p[i].num=i; } sort(p+1,p+m+1,cmp); int l=1; for (int i=1;i<=n;i++) { while(len && a[t[len]]<a[i])len--; gengxin(1,1,n,t[len]+1,i); t[++len]=i; while(l<=m && p[l].r<=i) { ans[p[l].num]=chaxun(1,1,n,p[l].l,p[l].r); l++; } } for (int i=1;i<=m;i++)printf("%d ",ans[i]); return 0; }