LOJ #6285 分块入门9
题意:区间众数,不带修改,带修改刚看了一眼没看懂cls在讲啥QAQ。
题解:按照代码中那个sqrt(n/2/log2(n))大小分块,可以用均值不等式证明的,就是假设查询和n同级,然后一通爆算就可以得出了。然后预处理出(i,j)块之间最多的数。然后不满一块的部分在vector上二分,这题要先离散化。PS:loj上可以看别人代码学习速度++ 啊。因为把hzwer的1-9看了一遍,时间有限,就随便挑一个了,然后bzoj上的题是权限题,就注册了loj找了份简洁的学着写了,不太习惯,然后有更优秀的做法,看hzwer博客以及cls的论文吧,如果这样预处理直接sqrt(n)是TLE的,应该是卡掉了。
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1e5+7; inline ll read() { ll 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; } int n,m; vector<int >vec[maxn]; int gs(int x,int l,int r) { return upper_bound(vec[x].begin(),vec[x].end(),r)-lower_bound(vec[x].begin(),vec[x].end(),l); } int a[maxn],b[maxn],bl[maxn]; int f[2000][2000]; int s[maxn]; int get(int l,int r) { if(bl[l]==bl[r]) { int ans=0,ans1=0; for(int i=l;i<=r;i++) { int tmp=gs(a[i],l,r); if(tmp>ans1){ ans=a[i];ans1=tmp; } if(tmp==ans1)ans=min(a[i],ans); } return ans; } int ans0=f[bl[l]+1][bl[r]-1],ans1=gs(ans0,l,r); for(int i=l;bl[i]==bl[l];i++) { int tmp=gs(a[i],l,r); if(tmp>ans1) { ans0=a[i];ans1=tmp; } if(tmp==ans1)ans0=min(a[i],ans0); } for(int i=r;bl[i]==bl[r];i--) { int tmp=gs(a[i],l,r); if(tmp>ans1)ans0=a[i],ans1=tmp; if(tmp==ans1)ans0=min(a[i],ans0); } return ans0; } int main() { n=read(); int d=(int)sqrt(n/2/log2(n)); for(int i=1;i<=n;i++) { a[i]=read();b[i]=a[i];bl[i]=(i-1)/d+1; } sort(b+1,b+1+n); int ts=unique(b+1,b+1+n)-b-1; for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+ts,a[i])-b; for(int i=1;i<=n;i++) vec[a[i]].push_back(i); for(int i=1;i<=bl[n];i++) { memset(s,0,sizeof(s)); int ans1=0,ans2=0; for(int j=(i-1)*d+1;j<=n;j++) { s[a[j]]++; if(s[a[j]]==ans2) { ans1=min(a[j],ans1); } else if(s[a[j]]>ans2) { ans1=a[j];ans2=s[a[j]]; } if(bl[j+1]!=bl[j]) f[i][bl[j]]=ans1; } } int p=0,q=0; for(int i=1;i<=n;i++) { p=read();q=read(); if(p>q)swap(p,q); cout<<b[get(p,q)]<<"\n"; } }