jzoj 4999. 【NOI2017模拟3.3】螺旋序列 不删除版莫队算法

题意

有一个长度为n的序列a,一个长度为m序列b被称为螺旋序列当且仅当b1=bm且对于1<=i<=m有bi<=b1。 S需要回答q个询问,每个询问用l,r两个参数描述,表示询问区间[l,r]的最长连续子螺旋序列的长度。 n,m<=5*10^5;|ai|<=10^9

分析

一开始看到这个数据范围估计没人敢去打莫队,不过事实告诉我们人还是要有点信仰才行。

先用rmq或主席树之类的方法预处理出next和last数组,next[i]表示一个最小的j满足a[j]==a[i]且max(a[i..j])==a[i],last同理。 然后就可以上莫队了。 然后会发现这题用莫队不资瓷删除,于是我们就只能用不删除的莫队。 那不删除的莫队要怎么做呢? 对每个询问按照左端点所在的块为第一关键字右端点为第二关键字排序,然后对于左右端点在同一块内的询问暴力处理。对于处理左端点在同一块内的询问,显然右端点只需要往右移也就是添加,每次询问的时候都先把左端点弄到该块的最右边,然后不断左移,同时左移的时候不该边全局变量,询问玩后暴力恢复即可。 对于这题而言我们需要维护若干条链,那么我们用一个数组fa[i]记录第i个位置所在链的根节点,f[i]记录答案。若右端点右移则更新其所在链;若左端点左移则其f值为其后继的f值加上两段间的长度,最后暴力恢复f即可。 时间复杂度O(nn√)

代码

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define N 500005 using namespace std; int n,m,rmq[N][30],bel[N],a[N],f[N],fa[N],next[N],last[N],ls[N],block,vis[N],b[N]; struct query{int l,r,ans,id;}q[N]; int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } bool cmp(query a,query b) { return bel[a.l]<bel[b.l]||bel[a.l]==bel[b.l]&&a.r<b.r; } bool cmpid(query a,query b) { return a.id<b.id; } void get_rmq() { int lg=log(n)/log(2); for (int i=1;i<=n;i++) rmq[i][0]=a[i]; for (int j=1;j<=lg;j++) for (int i=1;i<=n-(1<<j)+1;i++) rmq[i][j]=max(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]); } int get_max(int l,int r) { int lg=log(r-l+1)/log(2); return max(rmq[l][lg],rmq[r-(1<<lg)+1][lg]); } int get_ans(int x) { int l=q[x].l,r=q[x].r,mx=1; for (int i=l;i<=r;i++) vis[i]=0; for (int i=l;i<=r;i++) if (!vis[i]) { vis[i]=1; if (next[i]&&next[i]<=r) { int j=next[i]; while (next[j]&&next[j]<=r) vis[j]=1,j=next[j]; mx=max(mx,j-i+1); } } q[x].ans=mx; } void solve() { int ans=1,l,r=block*bel[q[1].l]+1; for (int j=1;j<=n;j++) fa[j]=j,f[j]=1; for (int i=1;i<=m;i++) { if (bel[q[i-1].l]!=bel[q[i].l]) { for (int j=1;j<=n;j++) fa[j]=j,f[j]=1; ans=1;r=block*bel[q[i].l]; } if (bel[q[i].l]==bel[q[i].r]) { get_ans(i); continue; } l=block*bel[q[i].l]+1; while (r<q[i].r) { r++; if (last[r]>=l) fa[r]=fa[last[r]],f[fa[r]]+=r-last[r],ans=max(ans,f[fa[r]]); } int ans2=ans; while (l>q[i].l) { l--; if (next[l]&&next[l]<=r) f[l]=f[next[l]]+next[l]-l,ans2=max(ans2,f[l]); } q[i].ans=ans2; int t=block*bel[q[i].l]; while (l<=t) f[l]=1,l++; } } int main() { freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout); n=read();m=read();block=sqrt(n); for (int i=1;i<=n;i++) b[i]=a[i]=read(); sort(b+1,b+n+1); int b1=unique(b+1,b+n+1)-b-1; for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+b1+1,a[i])-b; get_rmq(); for (int i=1;i<=n;i++) { int x=a[i]; if (get_max(ls[x],i)==x) last[i]=ls[x],next[ls[x]]=i; bel[i]=(i+block-1)/block;ls[x]=i; } for (int i=1;i<=m;i++) { q[i].l=read();q[i].r=read();q[i].id=i; } sort(q+1,q+m+1,cmp); solve(); sort(q+1,q+m+1,cmpid); for (int i=1;i<=m;i++) PRintf("%d\n",q[i].ans); }