zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    数据结构-堆(优先队列)习题
    数据结构-二叉搜索树习题
    数据结构-树习题
    数据结构-队列习题
    数据结构-堆栈习题
    数据结构-链表习题
    数据结构-顺序表习题
    数据结构-概论习题
    C语言中的stdin,stdout,stderr[转]
    SQL Server 查询数据库表结构
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5378104.html
Copyright © 2011-2022 走看看