[loj6746]区间众数
作者:互联网
枚举区间中点$x$,考虑$L$使得$x$为区间$[x-L,x+L]$的众数:
记可重集$\{|i-x|\mid a_{i}=x\}$中的元素依次为$b_{1}\le b_{2}\le ...\le b_{k}$
枚举出现次数$i\in [1,k]$,即要求$L\in [b_{i},b_{i+1})$,且合法的$L$是该区间的一个前缀
当$k\ge \sqrt{n}$时,这类$x$仅有$o(\sqrt{n})$个,直接从小到大枚举$L$并维护众数即可
当$k<\sqrt{n}$时,预处理出$pos_{r,i}$表示以$r$为右端点且众数出现次数$>i$的左端点
此时,条件即$pos_{x+L,i}<x-L$,移项后$L+pos_{x+L,i}$具有单调性,二分即可
具体实现中,$pos$可以用双指针求出,且需交换$i$和$x$的枚举顺序(空间限制)
上述过程复杂度为$o(n\sqrt{n})$(注意二分仅有$n$次),并转换为以下问题:
给定$n$组$(x,l_{L},r_{L})$,$m$次询问$\sum_{(x,l_{L},r_{L})}[l_{L},r_{L}]\cap [0,\min(x-l,r-x)]$
记$mid=\lfloor\frac{l+r}{2}\rfloor$,对$x\in [l,mid]/(mid,r]$分类讨论,以下以前者为例——
对$[l_{L},r_{L}]$差分并用$x$减去两项,最终结果即$\max(x-l_{L}+1,l)-\max(x-r_{L},l)$
在此基础上,对$x$差分并做扫描线,用树状数组维护上述两值即可
总复杂度为$o(n\sqrt{n}+m\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 #define ll long long 5 #define pii pair<int,int> 6 #define fi first 7 #define se second 8 int n,m,K,l,r,num[21],a[N],cnt[N],pos[N];ll ans[N<<1]; 9 vector<int>v[N];vector<pii>vu[N],vq1[N],vq2[N]; 10 struct TA{ 11 ll f[N]; 12 int lowbit(int k){ 13 return (k&(-k)); 14 } 15 void update(int k,int x){ 16 while (k<=n+1)f[k]+=x,k+=lowbit(k); 17 } 18 ll query(int k){ 19 ll ans=0; 20 while (k)ans+=f[k],k^=lowbit(k); 21 return ans; 22 } 23 ll query(int l,int r){ 24 return query(r)-query(l-1); 25 } 26 }F1,F2,F3,F4; 27 int read(){ 28 int x=0;char c=getchar(); 29 while ((c<'0')||(c>'9'))c=getchar(); 30 while ((c>='0')&&(c<='9'))x=x*10+c-'0',c=getchar(); 31 return x; 32 } 33 void write(ll x,char c='\0'){ 34 while (x)num[++num[0]]=x%10,x/=10; 35 if (!num[0])putchar('0'); 36 while (num[0])putchar(num[num[0]--]+'0'); 37 putchar(c); 38 } 39 int main(){ 40 n=read(),m=read(),K=(int)sqrt(n); 41 for(int i=1;i<=n;i++){ 42 a[i]=read(); 43 v[a[i]].push_back(abs(i-a[i])); 44 } 45 for(int i=1;i<=n;i++) 46 if (v[i].size()<K)sort(v[i].begin(),v[i].end()); 47 else{ 48 int mx=0,lst=-1; 49 memset(cnt,0,sizeof(cnt)); 50 for(int j=0;j<=min(i-1,n-i);j++){ 51 mx=max(mx,++cnt[a[i-j]]); 52 if (j)mx=max(mx,++cnt[a[i+j]]); 53 if (cnt[i]==mx){ 54 if (lst<0)lst=j; 55 } 56 else{ 57 if (lst>=0)vu[i].push_back(make_pair(lst,j-1)),lst=-1; 58 } 59 } 60 if (lst>=0)vu[i].push_back(make_pair(lst,min(i-1,n-i))); 61 } 62 for(int i=1;i<K;i++){ 63 int now=1,s=0; 64 memset(cnt,0,sizeof(cnt)); 65 for(int j=1;j<=n;j++){ 66 s+=(cnt[a[j]]++==i); 67 while (s>(cnt[a[now]]==i+1))s-=(--cnt[a[now++]]==i); 68 pos[j]=(s ? now : -0x3f3f3f3f); 69 } 70 for(int j=1;j<=n;j++) 71 if ((v[j].size()<K)&&(v[j].size()>=i)){ 72 int l=v[j][i-1],r=min(j-1,n-j); 73 if (i<v[j].size())r=min(r,v[j][i]-1); 74 if ((l>r)||(pos[j+l]>=j-l))continue; 75 while (l<r){ 76 int mid=(l+r+1>>1); 77 if (pos[j+mid]<j-mid)l=mid; 78 else r=mid-1; 79 } 80 vu[j].push_back(make_pair(v[j][i-1],l)); 81 } 82 } 83 for(int i=1;i<=m;i++){ 84 l=read(),r=read(); 85 int mid=(l+r>>1); 86 vq1[l-1].push_back(make_pair(l,-i)); 87 vq1[mid].push_back(make_pair(l,i)); 88 vq2[mid].push_back(make_pair(r,-i)); 89 vq2[r].push_back(make_pair(r,i)); 90 } 91 for(int i=1;i<=n;i++){ 92 for(pii j:vu[i]){ 93 F1.update(i-j.fi+1,1),F2.update(i-j.fi+1,i-j.fi+1); 94 F1.update(i-j.se,-1),F2.update(i-j.se,j.se-i); 95 F3.update(i+j.se,1),F4.update(i+j.se,i+j.se); 96 if (i+j.fi>1)F3.update(i+j.fi-1,-1),F4.update(i+j.fi-1,1-i-j.fi); 97 } 98 for(pii j:vq1[i]){ 99 int l=j.fi,id=abs(j.se); 100 ans[id]+=(j.se/id)*(l*F1.query(1,l)+F2.query(l+1,n+1)); 101 } 102 for(pii j:vq2[i]){ 103 int r=j.fi,id=abs(j.se); 104 ans[id]+=(j.se/id)*(r*F3.query(r+1,n+1)+F4.query(1,r)); 105 } 106 } 107 for(int i=1;i<=m;i++)write(ans[i],'\n'); 108 return 0; 109 }View Code
标签:int,众数,mid,back,pair,pos,loj6746,区间,id 来源: https://www.cnblogs.com/PYWBKTDA/p/16425549.html