区间第k小 分块
来源:互联网 发布:网络婚恋诈骗广东 编辑:程序博客网 时间:2024/06/06 02:34
题意
强制在线
分析
首先考虑离线做法。可以莫队+分块做。
莫队在指针动的同时,维护一个权值分块,然后每次O(1)修改,查询的时候可以O(sqrt(n))查询。这样复杂度就是O(sqrt(n))。
现在加上了强制在线,我们可以把莫队改成分块。
预处理g[i,j,k]表示序列分块中第k块到第j块有多少个数字在权值分块的第k块中,s[i,j]表示前i块中j出现的次数。
那么我们可以通过s和g来得到询问区间的权值分块数组,然后每次O(sqrt(n))询问即可。
yjq大爷告诉我们,像这种复杂度为log^2的题目,可以尝试着用分块来做,复杂度并不会相差太多。
代码
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int N=100005;const int M=325;int n,m,ty,w,bel[N],sta[M],end[N],s[M][N],g[M][M][M],block,t[N],sum[M],a[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;}void prework(){ block=sqrt(n); for (int i=1;i<=n;i++) { bel[i]=(i+block-1)/block; if (!sta[bel[i]]) sta[bel[i]]=i; end[bel[i]]=i; } for (int i=1;i<=bel[n];i++) { for (int j=sta[i];j<=end[i];j++) s[i][a[j]]++; for (int j=1;j<=n;j++) s[i][j]+=s[i-1][j]; } for (int i=1;i<=bel[n];i++) { for (int j=i;j<=bel[n];j++) { for (int k=1;k<=bel[n];k++) g[i][j][k]=g[i][j-1][k]; for (int k=sta[j];k<=end[j];k++) { t[a[k]]++; if (t[a[k]]==w+1) g[i][j][bel[a[k]]]-=w; else if (t[a[k]]<=w) g[i][j][bel[a[k]]]++; } } for (int j=sta[i];j<=n;j++) t[a[j]]--; }}int solve(int l,int r,int k){ memset(sum,0,sizeof(sum)); if (bel[l]!=bel[r]) { for (int i=1;i<=bel[n];i++) sum[i]=g[bel[l]+1][bel[r]-1][i]; for (int i=l;i<=end[bel[l]];i++) { if (!t[a[i]]) t[a[i]]=s[bel[r]-1][a[i]]-s[bel[l]][a[i]]; t[a[i]]++; if (t[a[i]]==w+1) sum[bel[a[i]]]-=w; else if (t[a[i]]<=w) sum[bel[a[i]]]++; } for (int i=sta[bel[r]];i<=r;i++) { if (!t[a[i]]) t[a[i]]=s[bel[r]-1][a[i]]-s[bel[l]][a[i]]; t[a[i]]++; if (t[a[i]]==w+1) sum[bel[a[i]]]-=w; else if (t[a[i]]<=w) sum[bel[a[i]]]++; } } else { for (int i=l;i<=r;i++) { t[a[i]]++; if (t[a[i]]==w+1) sum[bel[a[i]]]-=w; else if (t[a[i]]<=w) sum[bel[a[i]]]++; } } for (int i=1;i<=bel[n];i++) if (sum[i]<k) k-=sum[i]; else { for (int j=sta[i];j<=end[i];j++) { if (!t[j]) t[j]=max(s[bel[r]-1][j]-s[bel[l]][j],0); if (t[j]>w) continue; if (t[j]<k) k-=t[j]; else { for (int k=sta[i];k<=end[i];k++) t[k]=0; for (int k=l;k<=end[bel[l]];k++) t[a[k]]=0; for (int k=sta[bel[r]];k<=r;k++) t[a[k]]=0; return j; } } break; } for (int k=l;k<=end[bel[l]];k++) t[a[k]]=0; for (int k=sta[bel[r]];k<=r;k++) t[a[k]]=0; return n+1;}int main(){ freopen("kth.in","r",stdin);freopen("kth.out","w",stdout); n=read();w=read();m=read();ty=read(); for (int i=1;i<=n;i++) a[i]=read()+1; prework(); int ans=0; while (m--) { int l=read()^(ans*ty),r=read()^(ans*ty),k=read()^(ans*ty); printf("%d\n",ans=solve(l,r,k)-1); } return 0;}
阅读全文
0 0
- 分块 区间第k小
- 区间第k小 分块
- 【JZOJ5260】【GDOI2018模拟8.12】区间第k小(分块)
- 区间第k小
- 区间第K值带修改 分块
- 动态区间第K小数 分块/树套树
- 动态区间第k小 分块 O(nlogn*sqrt(nlogn))
- ZOJ 2112 Dynamic Rankings 动态区间第k大 分块
- zoj2112(单点修改区间第K小)
- 主席树模板 区间第k小
- 【GDOI2018模拟8.12】区间第k小
- 【GDOI2018模拟8.12】区间第k小
- 【JZOJ 5260】 区间第k小
- 划分树的学习(求区间第k大的数字)&&分块求区间第k大
- poj 2104 <排序分块,区间第k大>/<第一次用主席树>2个方法
- poj2761——treap,区间第K小值
- 查找给定区间内第K大/小的数
- poj 2104 区间第K小 主席树入门题
- java基础学习总结——基础语法2
- C#快速开发PictureBox 图像控件
- 浅谈游戏中BOSS设计的思路
- 桶排序在海量数据中的应用
- X509证书--ANS1结构
- 区间第k小 分块
- Hive自定义函数(generic)
- Java数组的常用方法
- 【NOIP模拟考三】水资源——二分答案+Floyd验证 day1 first 信号连接
- ORA-00845: MEMORY_TARGET not supported on this system
- IntelliJ IDEA Maven项目下文件夹不能右键新建java文件等文件的解决办法
- 一个小问题:随机输出一个数组中全部数值?
- linux使用shell的基本功能
- HDU1257 最少拦截系统 DP(最大递增子序列)