jzoj 4999. 【NOI2017模拟3.3】螺旋序列 不删除版莫队算法
来源:互联网 发布:淘宝300解id锁是可靠吗 编辑:程序博客网 时间:2024/05/16 07:11
题意
有一个长度为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即可。
时间复杂度
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>#define N 500005using 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);}
0 0
- jzoj 4999. 【NOI2017模拟3.3】螺旋序列 不删除版莫队算法
- jzoj 5023. 【NOI2017模拟3.18】Squence 莫队算法
- 【JZOJ 100019】【NOI2017模拟6.26】A
- JZOJ 100019【NOI2017模拟6.26】A
- JZOJ 5043. 【NOI2017模拟4.4】保持平衡
- 【NOI2017模拟6.3】子序列
- JZOJ 4915. 【GDOI2017模拟12.9】最长不下降子序列
- jzoj 4996. 【NOI2017模拟3.1】游戏 扫描线+treap
- jzoj 5000. 【NOI2017模拟3.4】保镖 hall定理+搜索
- jzoj 5001. 【NOI2017模拟3.4】Trie树 状压dp
- jzoj 5006. 【NOI2017模拟3.8】A 树形dp
- jzoj 5012. 【NOI2017模拟3.13】远行 启发式合并
- jzoj 5015. 【NOI2017模拟3.15】决斗 贪心+平衡树
- jzoj 5020. 【NOI2017模拟3.17】牛奶装瓶 线段树
- jzoj 5039. 【NOI2017模拟4.2】查询 线段树
- jzoj 5040. 【NOI2017模拟4.2】押韵 trie树+树形dp
- jzoj 5045. 【NOI2017模拟4.5】无限棋盘 hash+倍增
- 【NOI2017模拟6.3】子序列 矩阵乘法+DP
- 从Java 到Android 一个程序员的自我整理。
- 第5节-高斯判别分析和朴素贝叶斯
- redis常用命令
- 分治法-leetcode
- find & rm 组合删除目录
- jzoj 4999. 【NOI2017模拟3.3】螺旋序列 不删除版莫队算法
- 如何强制360浏览器以极速模式打开页面(lofter博客转移飞碟)
- c# 无法加载DLL“xxxx”:找不到指定的模块(异常来自HRESULT:0X8007007E)的一个解决方法
- Java 7之多线程
- 工具推荐:LICEcap-录屏为动态图片
- Dialog自定义setView点击事件空指针
- C++类中的数据成员能否在定义类的时候就初始化?
- 解决win7下Allegro中光标由小十字改为满屏十字后出现残影的问题
- 通过gradle下载jar包