[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 }

 

posted @ 2018-04-07 13:19  ww3113306  阅读(240)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。