ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[loj6746]区间众数

2022-06-30 08:32:48  阅读:146  来源: 互联网

标签:int 众数 mid back pair pos loj6746 区间 id


枚举区间中点$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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有