其他分享
首页 > 其他分享> > [loj6746]区间众数

[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