bzoj2724: [Violet 6]蒲公英 分块 区间众数 论algorithm与vector的正确打开方式
这个,要处理各个数的话得先离散,我用的桶。
我们先把每个块里的和每个块区间的众数找出来,那么在查询的时候,可能成为[l,r]区间的众数的数只有中间区间的众数和两边的数。
证明:若不是这里的数连区间的众数都达不到。
我已开始把某个离散后的值当成了坐标,调了好久.......
#include<cstdio> #include<cmath> #include<vector> #include<cstring> #include<algorithm> using namespace std; int b[40010],a[40010],n,m,lon,pos[40010],t,p[40010],back[40010],num[40010],f[210][210],sz; int cmp(const int x,const int y) { if(b[x]<b[y])return 1; if(b[x]==b[y]&&x<y)return 1; return 0; } vector<int> place[40010]; inline void do_it(int x) { memset(num,0,sizeof(num)); int who=0,how=0; for(int i=(x-1)*lon+1;i<=n;i++) { num[a[i]]++; if(num[a[i]]>how||(num[a[i]]==how&&back[a[i]]<back[who])) who=a[i],how=num[a[i]]; f[x][pos[i]]=who; } } inline void Init() { scanf("%d%d",&n,&m); lon=(int)sqrt(n+0.5); for(int i=1;i<=n;i++) { scanf("%d",&b[i]); p[i]=i; pos[i]=(i-1)/lon+1; } sort(p+1,p+n+1,cmp); for(int i=1;i<=n;i++) { if(b[p[i]]!=b[p[i-1]]) { a[p[i]]=++sz; back[sz]=b[p[i]]; } else a[p[i]]=sz; place[sz].push_back(p[i]); } t=pos[n]; for(int i=1;i<=t;i++)do_it(i); } inline int query(int l,int r,int x) { return upper_bound(place[x].begin(),place[x].end(),r)-lower_bound(place[x].begin(),place[x].end(),l); } inline int Min(int x,int y){return x<y?x:y;} inline int work(int l,int r) { int z=pos[l]+1,y=pos[r]-1; int who=f[z][y],how=query(l,r,who); int zzh=(z-1)*lon; zzh=Min(zzh,r); for(int i=l;i<=zzh;i++) { int x=query(l,r,a[i]); if(x>how||(x==how&&a[i]<who)) who=a[i],how=x; } if(pos[l]!=pos[r]) { zzh=(y*lon)+1; for(int i=zzh;i<=r;i++) { int x=query(l,r,a[i]); if(x>how||(x==how&&a[i]<who)) who=a[i],how=x; } } return back[who]; } int main() { Init(); int k=0; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); x=(x+k-1)%n+1; y=(y+k-1)%n+1; if(x>y)x^=y^=x^=y; k=work(x,y); printf("%d\n",k); } return 0; }
苟利国家生死以, 岂因祸福避趋之。