bzoj2724: [Violet 6]蒲公英(分块)
传送门
md调了一个晚上最后发现竟然是空间开小了……明明算出来够的……
讲真其实我以前不太瞧得起分块,觉得这种基于暴力的数据结构一点美感都没有。然而今天做了这道分块的题才发现分块的暴力之美(如果我空间没有开小就更美了)
我们先将整个数组分块,设块的大小为$T$
我们先预处理出所有以块边界为端点的区间的答案,即$ans[L][R]$代表着第$L$块到第$R$块的序列所代表的答案。这个可以$O(n*n/T)$预处理
然后我们先将所有的数给离散化,然后对每一个值都开一个vector,记录这个值在数组中出现的每一个位置。比如数组的下标为1,3,5的位置都是3,那么3的vector记录的就是{1,3,5}
这个有什么用呢?我们设查询的区间为$[l,r]$,然后在这个vector里先二分查找第一个大于等于$l$的数的位置,再二分查找第一个大于$r$的数的位置,那么两个位置一减就是这个数在这个区间中的出现次数。比如查询区间$[2,4]$,我们先找到第一个大于等于2的数3,在vector中下标为2,再找第一个大于4的数为5,下标为3,那么3-2=1就是3这个数字在这个区间中的出现次数
那么,我们设$[L,R]$为查询区间之间的整块,因为我们第一步已经预处理出了所有块与块之间的答案,那么这一段之间的众数也就可以知道。那么,只有区间$[l,L-1]$和$[R+1,r]$之间的数字有可能更新答案。那么我们就去枚举这两个区间中的所有数字,然后用上面说的方法去查询它在整个查询区间内的出现次数,然后更新答案即可
复杂度为$O(n*n/T+n*T*logn)$,设块的大小为$n/sqrt{nlogn}$ ,那么时间复杂度就是$O(nsqrt{nlogn})$
其实还有一种更快的方法是先预处理出块与块之间的答案和各个数的出现次数,然后查询只要在散块里暴力增加并更新答案,之后暴力复原即可(然而我懒并不想打)
然后基本注意点都写在注解里了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<vector> 7 #include<cmath> 8 #define inf 0x3f3f3f3f 9 using namespace std; 10 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 11 char buf[1<<21],*p1=buf,*p2=buf; 12 inline int read(){ 13 #define num ch-'0' 14 char ch;bool flag=0;int res; 15 while(!isdigit(ch=getc())) 16 (ch=='-')&&(flag=true); 17 for(res=num;isdigit(ch=getc());res=res*10+num); 18 (flag)&&(res=-res); 19 #undef num 20 return res; 21 } 22 char sr[1<<21],z[20];int C=-1,Z; 23 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 24 inline void print(int x){ 25 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 26 while(z[++Z]=x%10+48,x/=10); 27 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 28 } 29 const int N=40005,M=1005; 30 int ans[M][M],a[N],b[N],cnt[N],rt[N],vis[N]; 31 vector<int> pos[N]; 32 int n,m,q,lastans=0,s,l,r; 33 inline int query_cnt(int x){ 34 //查询数的出现次数,注意l和r要开全局变量 35 return upper_bound(pos[x].begin(),pos[x].end(),r)-lower_bound(pos[x].begin(),pos[x].end(),l); 36 } 37 void init(){ 38 //暴力枚举块与块之间的答案 39 for(int i=1;i<=rt[n];++i){ 40 memset(cnt,0,sizeof(cnt)); 41 int bg=s*(i-1)+1,res=a[bg]; 42 for(int j=bg;j<=n;++j){ 43 ++cnt[a[j]]; 44 if(cnt[a[j]]>cnt[res]||(cnt[a[j]]==cnt[res]&&a[j]<res)) res=a[j]; 45 ans[i][rt[j]]=res; 46 } 47 } 48 } 49 int query(int l,int r){ 50 //查询,小块暴力,大块直接找答案 51 if(rt[r]-rt[l]<=1){ 52 int id=0,res=0; 53 for(int i=l;i<=r;++i) 54 if(!vis[a[i]]){ 55 int t=query_cnt(a[i]); 56 if(t>res||(t==res&&a[i]<id)) res=t,id=a[i]; 57 vis[a[i]]=1; 58 } 59 for(int i=l;i<=r;++i) vis[a[i]]=0; 60 return b[id]; 61 } 62 int L=rt[l]+1,R=rt[r]-1; 63 int LL=(L-1)*s+1,RR=R*s; 64 int id=ans[L][R],res=query_cnt(id);vis[id]=1; 65 for(int i=l;i<LL;++i) 66 if(!vis[a[i]]){ 67 int t=query_cnt(a[i]); 68 if(t>res||(t==res&&a[i]<id)) res=t,id=a[i]; 69 vis[a[i]]=1; 70 } 71 for(int i=RR+1;i<=r;++i) 72 if(!vis[a[i]]){ 73 int t=query_cnt(a[i]); 74 if(t>res||(t==res&&a[i]<id)) res=t,id=a[i]; 75 vis[a[i]]=1; 76 } 77 for(int i=l;i<LL;++i) vis[a[i]]=0; 78 for(int i=RR+1;i<=r;++i) vis[a[i]]=0; 79 vis[ans[L][R]]=0; 80 return b[id]; 81 } 82 int main(){ 83 n=read(),q=read(),s=sqrt(n/(double)(log2(n))+1); 84 //我怕s会变成0所以sqrt里加了个1(可能并不需要) 85 for(int i=1;i<=n;++i) a[i]=b[i]=read(),rt[i]=(i-1)/s+1;//分块 86 sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1; 87 for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+m,a[i])-b,pos[a[i]].push_back(i); 88 //以上是离散 89 init(); 90 while(q--){ 91 l=read(),r=read(); 92 l=(l+lastans-1)%n+1,r=(r+lastans-1)%n+1; 93 if(l>r) swap(l,r); 94 print(lastans=query(l,r)); 95 } 96 Ot(); 97 return 0; 98 }
转载于:https://www.cnblogs.com/bztMinamoto/p/9607299.html
bzoj2724: [Violet 6]蒲公英(分块)相关推荐
- [BZOJ2724][Violet 6]蒲公英
[BZOJ2724][Violet 6]蒲公英 试题描述 输入 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 输出 输入示 ...
- Bzoj 2724: [Violet 6]蒲公英(分块)
2724: [Violet 6]蒲公英 Time Limit: 40 Sec Memory Limit: 512 MB Description Input 修正一下 l = (l_0 + x - 1) ...
- 【bzoj2724】[Violet 6]蒲公英 分块+STL-vector
题目描述 输入 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 输出 样例输入 6 3 1 2 3 2 1 2 1 5 3 ...
- bzoj 2724: [Violet 6]蒲公英(分块预处理)
2724: [Violet 6]蒲公英 Time Limit: 40 Sec Memory Limit: 512 MB Submit: 2464 Solved: 848 [Submit][Stat ...
- bzoj 2724[Violet 6]蒲公英
2724: [Violet 6]蒲公英 Time Limit: 40 Sec Memory Limit: 512 MB Submit: 2630 Solved: 920 [Submit][Stat ...
- 【分块】【Violet】蒲公英
[描述] 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了.我觉得把那么可怕 ...
- Luogu P4168 [Violet]蒲公英(分块)
P4168 [Violet]蒲公英 题意 题目背景 亲爱的哥哥: 你在那个城市里面过得好吗? 我在家里面最近很开心呢.昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还 ...
- 洛谷 - P4168 [Violet]蒲公英(分块+离散化)
题目链接:点击查看 题目大意:给出一个长度为 n 的数列,再给出 m 次查询,每次查询区间 [ l , r ] 内的众数,要求强制在线 题目分析:对于这个题意来说,如果允许离线的话,完全可以用莫队当模 ...
- Luogu P4168 [Violet]蒲公英 分块
这道题算是好好写了.写了三种方法. 有一个好像是$qwq$$N\sqrt(N)$的方法,,但是恳请大佬们帮我看看为什么这么慢$qwq$(后面的第三种) 注:$pos[i]$表示$i$属于第$pos[i ...
最新文章
- 中国民航大学计算机学院宿舍,中国民航大学计算机科学与技术学院研究生导师简介-谢丽霞_清华大学宿舍...
- 渗透知识-编译器漏洞
- Java开发代码规范之编程规约---命名风格
- find out the service list changed with given user which have item category group
- Self Introduction
- 编程语言的“别样”编年史
- Preparing Cities for Robot Cars【城市准备迎接自动驾驶汽车】
- leetcode 11
- vivoy9s怎么设置返回键_vivoy9s怎么设置返回键 可以使用虚拟导航键
- MySQL表联合查询 理论基础:外键、操作关联表(一)
- 深度优先搜索(DFS)和广度优先搜索(BFS)探究
- python二分法代码_Python的算法之二分法
- 【从零开始学架构-李运华】07|低成本、安全、规模
- ecshop二次开发手册,基本结构
- 计算机专业在医院的工作,探析计算机在医院工作的应用
- win7 此计算机无法连接到家庭组,Win7旗舰版无法进入家庭组如何处理
- 矢量网络分析仪VNA的校准之SOLT方法
- 十二存单法 和 阶梯存款法
- C# 的1ms延时函数
- php中date设置北京时区,PHP中设置时区方法小结