• [Violet]蒲公英 分块


    发现写算法专题老是写不动,,,,

    所以就先把我在luogu上的题解搬过来吧!

    题目大意:查询区间众数,无修改,强制在线

    乍一看是一道恐怖的题,仔细一看发现并没有那么难;

    大致思路是这样的,首先我们要充分发挥分块暴力大法好的精神

    先暴力预处理出每个块内每种蒲公英的个数,

    然后求出对每个块而言的前缀和,

    于是这样我们就可以区间查询任意两个块之间每种蒲公英的数量了

    然后我们预处理出任意两个块之间的众数

    最后对于每组询问,我们先找到夹在它们中间的块,

    如果这个两个块r-l<=1,那么我们暴力求众数

    为什么? 因为不这样的话,万一x,y在一个快,那么r可能会比l小,要特判

    如果x,y隔得很近,同样有各种奇奇怪怪的情况要做特判,

    那既然这么麻烦,我们不如直接暴力搞是吧。

    如果两个块相差超过了1,那么我们先取出中间块的众数,作为我们的answer,然后对旁边两个块暴力处理众数(此处注意判断时要加上中间的蒲公英)。

    最后我们就得到了答案,

    但是注意到ai的范围很大,所以我们需要离散化。

    并且由于数量相同时要优先编号小的,于是我们处理众数的时候要多加这个判断

    基本就是这样了。。。

    表示本蒟蒻一A过了还是很开心的(^▽^)(虽然说第一次交没删调试结果too many or too few lines 了,但是去掉调试就过了,也可以算是一A嘛是吧)

    下面代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 40100
      5 #define ac 210
      6 #define D printf("line in %d\n",__LINE__);
      7 int block,n,m,answer,tot;
      8 int s[AC];
      9 struct abc{
     10     int num,w,x;
     11 }b[AC];//原数列+离散化后数组
     12 int sum[ac][AC];//每种数字块内前缀和
     13 int ans[ac][ac];//任意两块之间的众数
     14 int belong[AC];//所属块
     15 int color[AC];
     16 
     17 inline int read()
     18 {
     19     int x=0;char c=getchar();
     20     while(c>'9' || c<'0') c=getchar();
     21     while(c>='0' && c<='9') x=x*10+c-'0',c=getchar();
     22     return x;
     23 }
     24 
     25 bool cmp1(abc a,abc b)
     26 {
     27     return a.w < b.w;
     28 }
     29 
     30 bool cmp2(abc a,abc b)
     31 {
     32     return a.num < b.num;
     33 }
     34 
     35 void search(int x,int y)
     36 {
     37 //  printf("%d %d\n",x,y);
     38     int l=x/block + 1,r=y/block - 1;//取出中间块
     39     if(r - l <= 1)//如果x,y相差很小,那么暴力统计
     40     {
     41         answer=0;
     42         for(R i=x;i<=y;i++)
     43             if((++color[b[i].x] > color[answer]) || (color[b[i].x] == color[answer] && b[i].x < answer)) answer=b[i].x;
     44         for(R i=x;i<=y;i++)
     45             --color[b[i].x];
     46         printf("%d\n",s[answer]);
     47         return ;
     48     }
     49     else//不然的话
     50     {
     51         int ll=l * block - 1,rr=(r+1) * block;
     52         answer=ans[l][r];
     53         for(R i=x;i<=ll;i++)
     54         {
     55             ++color[b[i].x];
     56             if(color[b[i].x] + sum[r][b[i].x] - sum[l-1][b[i].x] > color[answer] + sum[r][answer] - sum[l-1][answer]) answer=b[i].x;
     57             else if(color[b[i].x] + sum[r][b[i].x] - sum[l-1][b[i].x] == color[answer] + sum[r][answer] - sum[l-1][answer] && b[i].x < answer) answer=b[i].x;//编号小也要优先,因为一行写不下,为了美观,,,就用else吧,不然就用||了
     58         }
     59         for(R i=rr;i<=y;i++)
     60         {
     61             ++color[b[i].x];
     62             if(color[b[i].x] + sum[r][b[i].x] - sum[l-1][b[i].x] > color[answer] + sum[r][answer] - sum[l-1][answer]) answer=b[i].x;
     63             else if(color[b[i].x] + sum[r][b[i].x] - sum[l-1][b[i].x] == color[answer] + sum[r][answer] - sum[l-1][answer] && b[i].x < answer) answer=b[i].x;
     64         }
     65         for(R i=x;i<=ll;i++) --color[b[i].x];
     66         for(R i=rr;i<=y;i++) --color[b[i].x];
     67         printf("%d\n",s[answer]);
     68         return ;
     69     }
     70 }
     71 
     72 void pre()//读入
     73 {
     74     n=read(),m=read();
     75     block=sqrt(n);
     76     for(R i=1;i<=n;i++) b[i].w=read(),b[i].num=i;
     77     sort(b+1,b+n+1,cmp1);
     78     for(R i=1;i<=n;i++)
     79     {
     80         if(b[i].w != b[i-1].w) 
     81         {
     82             s[++tot]=b[i].w;//存下对应新编号的对应真实编号 
     83             b[i].x=tot;
     84         }
     85         else b[i].x=b[i-1].x;//离散化
     86     }
     87     sort(b+1,b+n+1,cmp2);
     88 }
     89 
     90 void getsum()
     91 {//注意0也被分在块0中
     92     for(R i=1;i<=n;i++)
     93     {
     94         belong[i]=i/block;
     95         sum[belong[i]][b[i].x]++;
     96     }
     97     for(R i=0;i<=belong[n];i++)
     98         for(R j=1;j<=tot;j++)
     99             sum[i][j]+=sum[i-1][j];
    100 }
    101 
    102 void getans()
    103 {
    104     for(R i=0;i<=belong[n];i++)
    105     {
    106         int be=i * block,now=0;
    107         if(!be) be=1;//这里和作诗不同,因为这里的now要参与比较了,而不是单纯的统计,而now初始值为0,所以color[0]不能被修改
    108         for(R j=be;j<=n;j++)
    109         {
    110             if((++color[b[j].x] > color[now]) || (color[b[j].x] == color[now] && b[j].x < now)) now=b[j].x;//更新ans
    111             ans[i][belong[j]]=now;//存下新ans
    112         }
    113         for(R j=be;j<=n;j++) --color[b[j].x];//暴力撤销
    114     }
    115     /*for(R i=0;i<=belong[n];i++)
    116     {
    117         for(R j=i;j<=belong[n];j++)
    118             printf("%d ",ans[i][j]);
    119         printf("\n");
    120     }*/
    121 }
    122 
    123 void work()//预处理出前缀和和众数
    124 {
    125     int a,b;
    126     for(R i=1;i<=m;i++)
    127     {
    128         a=(read() + s[answer] -1) % n + 1,b=(read() + s[answer] - 1) % n + 1;//获取询问
    129         if(a < b) search(a,b);
    130         else search(b,a);//因为经过了运算,所以大小顺序就可能改变了
    131     }   
    132 }
    133 
    134 int main()
    135 {
    136 //  freopen("in.in","r",stdin);
    137     pre();
    138     getsum();
    139     getans();
    140     work();
    141 //  fclose(stdin);
    142     return 0;
    143 }
    本文不允许商业性使用,个人转载请注明出处! 知识共享许可协议
    本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。
  • 相关阅读:
    白兔的字符串(字符串hash+模拟map)
    [TJOI2013]单词(AC自动机+前缀和维护)
    [SDOI2014]数数(ac自动机+数位DP)
    阿狸的打字机(AC自动机+dfs序 + 维护区间值)
    string(AC自动机 在线询问转离线询问)
    E
    JMX超详细解读
    快速生成100万数据人员信息数据
    聊聊spring之bean对象的实例化过程
    聊聊spring之贯穿全局的重要对象BeanDefinition
  • 原文地址:https://www.cnblogs.com/ww3113306/p/8733027.html
Copyright © 2020-2023  润新知