• loj#6285. 数列分块入门 9


    #6285. 数列分块入门 9

    题目:传送门 

    简要题意:

       给出一个长为 n 的数列,以及 n 个操作,操作涉及询问区间的最小众数。


    题解:

       很开心,最后一题...分块刷的非常高(恶)兴(心)!

       据说原题是一道超级大难题...还是先做做简单的吧...

       首先用dp求出第i块到第j块的最小众数...

       然后神奇的stl开始来袭...

       依旧分情况走一波...

       对于我们需要处理的其中一段小区间,那么可以用一个vector将不同种类的数所出现的位置先存起来,那么就可以用upper_bound右端点-lower_bound左端点...(具体的就看代码吧)

       大槽点:对于不会用stl的蒟蒻...以为upper_bound如果找不到答案就会返回最后一个位置...自信的认为hzwer的代码是错的...结果...手测一波,发现返回的是末尾指针加1???好的hzwer大佬我错了ORZ


    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<map>
     7 #include<vector>
     8 using namespace std;
     9 int n,id,a[110000],ba[110000],cnt[51000];
    10 int block,pos[110000];
    11 int f[510][510];//第i块到第j块的最小众数是第几种数
    12 map<int,int>mp;
    13 vector<int>w[51000];
    14 void dp(int x)
    15 {
    16     memset(cnt,0,sizeof(cnt));
    17     int mx=0,ans=0;
    18     for(int i=(x-1)*block+1;i<=n;i++)
    19     {
    20         int cc=++cnt[a[i]];int k=pos[i];
    21         if(cc>mx || (cc==mx && ba[a[i]]<ba[ans]))mx=cc,ans=a[i];
    22         f[x][k]=ans;
    23     }
    24 }
    25 int getlong(int l,int r,int x)
    26 {
    27     int ans=upper_bound(w[x].begin(),w[x].end(),r)-lower_bound(w[x].begin(),w[x].end(),l);
    28     return ans;
    29 }
    30 int sol(int l,int r)
    31 {
    32     int ans=0,mx=0;
    33     ans=f[pos[l]+1][pos[r]-1];
    34     mx=getlong(l,r,ans);
    35     for(int i=l;i<=min(pos[l]*block,r);i++)        
    36     {
    37         int cc=getlong(l,r,a[i]);
    38         if(cc>mx || (cc==mx && ba[a[i]]<ba[ans]))mx=cc,ans=a[i];
    39     }
    40     if(pos[l]!=pos[r])
    41         for(int i=(pos[r]-1)*block+1;i<=r;i++)
    42         {
    43             int cc=getlong(l,r,a[i]);
    44             if(cc>mx || (cc==mx && ba[a[i]]<ba[ans]))mx=cc,ans=a[i];
    45         }
    46     return ans;
    47 }
    48 int main()
    49 {
    50     memset(ba,63,sizeof(ba));
    51     scanf("%d",&n);block=sqrt(n);id=0;
    52     for(int i=1;i<=n;i++)pos[i]=(i-1)/block+1;
    53     for(int i=1;i<=n;i++)
    54     {
    55         scanf("%d",&a[i]);
    56         if(!mp[a[i]])
    57         {
    58             mp[a[i]]=++id;
    59             ba[id]=a[i];
    60         }
    61         a[i]=mp[a[i]];
    62         w[a[i]].push_back(i);
    63     }
    64     for(int i=1;i<=pos[n];i++)dp(i);
    65     for(int i=1;i<=n;i++)
    66     {
    67         int l,r;
    68         scanf("%d%d",&l,&r);
    69         if(l>r)swap(l,r);
    70         printf("%d
    ",ba[sol(l,r)]);
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    Windows 驱动加载程序代码
    coding push 上传文件
    MinGW 可以编译驱动的
    通过使用 NTLite 工具实现精简Windows系统
    一些常用的注入技巧
    Python 图片转字符图
    MySQL数据库及注入方法
    路由器被蹭网后,我有被黑的风险吗?
    markdown 实现代码折叠效果
    Windows 签名伪造工具的使用,Python,签名
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8580822.html
Copyright © 2020-2023  润新知