您的位置:首页 > 其它

[bzoj4241] 历史研究

2016-04-11 13:57 567 查看
  分块大法好。。

  这题就是个带权的区间众数。。。离散化一下就是普通的区间众数了。

  分成根号n块,预处理mx[i][j]表示第i块~第j块 这段区间里的众数,pr[i][j]表示前i块里,数字j出现了多少次。

  所以每个询问的答案,要么是整块里的众数,要么是两侧零散的数。

  整块里面每个数出现的次数就是pr[],两侧的出现次数就直接暴力累加。

  分块果然好写= =

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=100233;
struct zs{
int v,pos;
}a[maxn];
ll b[maxn],cnt;
int l[333],r[333],id[maxn];
int mx[333][333],pr[333][maxn];
int num[maxn],mp[maxn];
int i,j,k,n,m,kuai,x,y;

int ra;char rx;
inline int read(){
rx=getchar(),ra=0;
while(rx<'0'||rx>'9')rx=getchar();
while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
}
bool cmp(zs a,zs b){return a.v==b.v?a.pos<b.pos:a.v<b.v;}
inline ll query(int x,int y){
register int i;;
int idl=(x+kuai-1)/kuai,idr=(y+kuai-1)/kuai, ans=mx[idl+1][idr-1];
if(idl==idr){
for(i=x;i<=y;i++)
++num[mp[i]],ans=b[ans]*num[ans]<b[mp[i]]*num[mp[i]]?mp[i]:ans;
ll sum=b[ans]*num[ans];
for(i=x;i<=y;i++)num[mp[i]]=0;
return sum;
}
for(i=x;i<=r[idl];i++)++num[mp[i]];
for(i=l[idr];i<=y;i++)++num[mp[i]];
ll sum=b[ans]*( pr[idr-1][ans]-pr[idl][ans]+num[ans] );//printf("  sum:%lld  %d %d  %d\n",sum,idl,idr,pr[idr-1][ans]-pr[idl][ans]+num[ans]);
for(i=x;i<=r[idl];num[mp[i]]=0,i++)if(num[mp[i]])
if( b[mp[i]]*( pr[idr-1][mp[i]]-pr[idl][mp[i]]+num[mp[i]] ) > sum )ans=mp[i],sum=b[ans]*( pr[idr-1][ans]-pr[idl][ans]+num[ans] );
for(i=l[idr];i<=y;num[mp[i]]=0,i++)if(num[mp[i]])
if( b[mp[i]]*( pr[idr-1][mp[i]]-pr[idl][mp[i]]+num[mp[i]] ) > sum )ans=mp[i],sum=b[ans]*( pr[idr-1][ans]-pr[idl][ans]+num[ans] );
return sum;
}
int main(){
register int j,k;
n=read(),m=read(),kuai=min(n,323);//kuai=1;
for(i=1;i<=n;i++)a[i].v=mp[i]=read(),a[i].pos=i,id[i]=(i+kuai-1)/kuai;
for(i=1;i<=id
;i++)l[i]=(i-1)*kuai+1,r[i]=min(n,i*kuai);
sort(a+1,a+1+n,cmp);
for(i=1;i<=n;mp[a[i].pos]=cnt,pr[id[a[i].pos]][cnt]++,i++)
if(a[i].v!=a[i-1].v)b[++cnt]=a[i].v;

for(i=1;i<=id
;i++)
for(mx[i][i]=mp[l[i]],j=l[i]+1;j<=r[i];j++)if(b[mp[j]]*pr[i][mp[j]]>b[mx[i][i]]*pr[i][mx[i][i]])mx[i][i]=mp[j];
for(i=2;i<=id
;i++)for(j=1;j<=cnt;j++)pr[i][j]+=pr[i-1][j];
for(i=1;i<id
;i++){
for(j=1;j<=cnt;j++)num[j]=pr[i][j]-pr[i-1][j];
for(j=i+1;j<=id
;/*printf("mx:%d %d  %lld\n",i,j,b[mx[i][j]]),*/j++)
for(mx[i][j]=mx[i][j-1],k=l[j];k<=r[j];k++)
num[mp[k]]++,mx[i][j]=b[mx[i][j]]*num[mx[i][j]]<b[mp[k]]*num[mp[k]]?mp[k]:mx[i][j];
}
//    printf("   %lld\n",b[mx[1][id
]]);
memset(num,0,(cnt+1)<<2);
while(m--)
x=read(),y=read(),
printf("%lld\n",query(x,y));
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: