[bzoj4241] 历史研究

  分块大法好。。

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

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

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

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

  分块果然好写= =

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const int maxn=100233;
 8 struct zs{
 9     int v,pos;
10 }a[maxn];
11 ll b[maxn],cnt;
12 int l[333],r[333],id[maxn];
13 int mx[333][333],pr[333][maxn];
14 int num[maxn],mp[maxn];
15 int i,j,k,n,m,kuai,x,y;
16 
17 int ra;char rx;
18 inline int read(){
19     rx=getchar(),ra=0;
20     while(rx<'0'||rx>'9')rx=getchar();
21     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
22 }
23 bool cmp(zs a,zs b){return a.v==b.v?a.pos<b.pos:a.v<b.v;}
24 inline ll query(int x,int y){
25     register int i;;
26     int idl=(x+kuai-1)/kuai,idr=(y+kuai-1)/kuai, ans=mx[idl+1][idr-1];
27     if(idl==idr){
28         for(i=x;i<=y;i++)
29             ++num[mp[i]],ans=b[ans]*num[ans]<b[mp[i]]*num[mp[i]]?mp[i]:ans;
30         ll sum=b[ans]*num[ans];
31         for(i=x;i<=y;i++)num[mp[i]]=0;
32         return sum;
33     }
34     for(i=x;i<=r[idl];i++)++num[mp[i]];
35     for(i=l[idr];i<=y;i++)++num[mp[i]];
36     ll sum=b[ans]*( pr[idr-1][ans]-pr[idl][ans]+num[ans] );//printf("  sum:%lld  %d %d  %d
",sum,idl,idr,pr[idr-1][ans]-pr[idl][ans]+num[ans]);
37     for(i=x;i<=r[idl];num[mp[i]]=0,i++)if(num[mp[i]])
38         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] );
39     for(i=l[idr];i<=y;num[mp[i]]=0,i++)if(num[mp[i]])
40         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] );
41     return sum;
42 }
43 int main(){
44     register int j,k;
45     n=read(),m=read(),kuai=min(n,323);//kuai=1;
46     for(i=1;i<=n;i++)a[i].v=mp[i]=read(),a[i].pos=i,id[i]=(i+kuai-1)/kuai;
47     for(i=1;i<=id[n];i++)l[i]=(i-1)*kuai+1,r[i]=min(n,i*kuai);
48     sort(a+1,a+1+n,cmp);
49     for(i=1;i<=n;mp[a[i].pos]=cnt,pr[id[a[i].pos]][cnt]++,i++)
50         if(a[i].v!=a[i-1].v)b[++cnt]=a[i].v;
51     
52     for(i=1;i<=id[n];i++)
53         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];
54     for(i=2;i<=id[n];i++)for(j=1;j<=cnt;j++)pr[i][j]+=pr[i-1][j];
55     for(i=1;i<id[n];i++){
56         for(j=1;j<=cnt;j++)num[j]=pr[i][j]-pr[i-1][j];
57         for(j=i+1;j<=id[n];/*printf("mx:%d %d  %lld
",i,j,b[mx[i][j]]),*/j++)
58             for(mx[i][j]=mx[i][j-1],k=l[j];k<=r[j];k++)
59                 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];
60     }
61 //    printf("   %lld
",b[mx[1][id[n]]]);
62     memset(num,0,(cnt+1)<<2);
63     while(m--)
64         x=read(),y=read(),
65         printf("%lld
",query(x,y));
66     return 0;
67 }
View Code
原文地址:https://www.cnblogs.com/czllgzmzl/p/5378104.html