【分块】bzoj2724 [Violet 6]蒲公英

分块,离散化,预处理出:

①前i块中x出现的次数(差分);

②第i块到第j块中的众数是谁,出现了多少次。

询问的时候,对于整块的部分直接获得答案;对于零散的部分,暴力统计每个数出现的次数,加上差分的结果,尝试更新ans。

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 int n,m,sum,sz,num[40001],l[220],r[220],plv[40001][220],mode[220][220],mplv[220][220];
  7 int a[40001],en,Time[40001],x,y,ma[40001],ans;
  8 struct Point{int v,p;}b[40001];
  9 bool operator < (const Point &a,const Point &b){return a.v<b.v;}
 10 int Res,Num;char C,CH[12];
 11 inline int G()
 12 {
 13     Res=0;C=‘*‘;
 14     while(C<‘0‘||C>‘9‘)C=getchar();
 15     while(C>=‘0‘&&C<=‘9‘){Res=Res*10+(C-‘0‘);C=getchar();}
 16     return Res;
 17 }
 18 inline void P(int x)
 19 {
 20     Num=0;if(!x){putchar(‘0‘);puts("");return;}
 21     while(x>0)CH[++Num]=x%10,x/=10;
 22     while(Num)putchar(CH[Num--]+48);
 23     puts("");
 24 }
 25 void makeblock()
 26 {
 27     sz=(int)sqrt((double)n); if(!sz) sz=1;
 28     for(sum=1;sum*sz<n;sum++)
 29       {
 30         l[sum]=r[sum-1]+1;
 31         r[sum]=sum*sz;
 32         for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
 33       }
 34     l[sum]=r[sum-1]+1;
 35     r[sum]=n;
 36     for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
 37 }
 38 void LiSan()
 39 {
 40     sort(b+1,b+n+1);
 41     for(int i=1;i<=n;i++)
 42       {
 43         if(b[i].v!=b[i-1].v) en++;
 44         ma[a[b[i].p]=en]=b[i].v;
 45       }
 46 }
 47 void makeplv()
 48 {
 49     for(int i=1;i<=n;i++)
 50       for(int j=num[i];j<=sum;j++)
 51         plv[a[i]][j]++;
 52 }
 53 void makemode()
 54 {
 55     for(int i=1;i<=sum;i++)
 56       {
 57         memset(Time,0,sizeof(Time));
 58         int modenow,modeplv=0;
 59         for(int j=i;j<=sum;j++)
 60           {
 61             for(int k=l[j];k<=r[j];k++)
 62               {
 63                 Time[a[k]]++;
 64                 if(Time[a[k]]>modeplv||(Time[a[k]]==modeplv&&a[k]<modenow))
 65                   {
 66                     modenow=a[k];
 67                     modeplv=Time[a[k]];
 68                   }
 69               }
 70             mode[i][j]=modenow;
 71             mplv[i][j]=modeplv;
 72           }
 73       } memset(Time,0,sizeof(Time));
 74 }
 75 int Getplv(const int &v,const int &L,const int &R){return plv[v][R]-plv[v][L-1];}
 76 int main()
 77 {
 78     n=G(); m=G();
 79     for(int i=1;i<=n;i++) {b[i].v=G(); b[i].p=i;}
 80     makeblock(); LiSan(); makeplv(); makemode();
 81     for(int i=1;i<=m;i++)
 82       {
 83         x=G(); y=G(); x=(x+ans-1)%n+1; y=(y+ans-1)%n+1;
 84         if(x>y) swap(x,y);
 85         int modenow,modeplv=0;
 86         if(num[x]+1>=num[y])
 87           {
 88             for(int j=x;j<=y;j++)
 89               {
 90                 Time[a[j]]++;
 91                 if(Time[a[j]]>modeplv||(Time[a[j]]==modeplv&&a[j]<modenow))
 92                   {
 93                     modenow=a[j];
 94                     modeplv=Time[a[j]];
 95                   }
 96               }
 97             for(int j=x;j<=y;j++) Time[a[j]]--;
 98           }
 99         else
100           {
101             modenow=mode[num[x]+1][num[y]-1];
102             modeplv=mplv[num[x]+1][num[y]-1];
103             for(int j=x;j<=r[num[x]];j++)
104               {
105                 Time[a[j]]++; int t=Time[a[j]]+Getplv(a[j],num[x]+1,num[y]-1);
106                 if(t>modeplv||(t==modeplv&&a[j]<modenow))
107                   {
108                     modenow=a[j];
109                     modeplv=t;
110                   }
111               }
112             for(int j=l[num[y]];j<=y;j++)
113               {
114                 Time[a[j]]++; int t=Time[a[j]]+Getplv(a[j],num[x]+1,num[y]-1);
115                 if(t>modeplv||(t==modeplv&&a[j]<modenow))
116                   {
117                     modenow=a[j];
118                     modeplv=t;
119                   }
120               }
121             for(int j=x;j<=r[num[x]];j++) Time[a[j]]--;
122             for(int j=l[num[y]];j<=y;j++) Time[a[j]]--;
123           }
124         P(ans=ma[modenow]);
125       }
126     return 0;
127 }
时间: 2024-10-10 22:35:55

【分块】bzoj2724 [Violet 6]蒲公英的相关文章

BZOJ2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 795  Solved: 248[Submit][Status] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input Sample Output HINT 修正下: n <= 40000, m <= 50000 S

bzoj2724: [Violet 6]蒲公英(分块)

传送门 md调了一个晚上最后发现竟然是空间开小了……明明算出来够的…… 讲真其实我以前不太瞧得起分块,觉得这种基于暴力的数据结构一点美感都没有.然而今天做了这道分块的题才发现分块的暴力之美(如果我空间没有开小就更美了) 我们先将整个数组分块,设块的大小为$T$ 我们先预处理出所有以块边界为端点的区间的答案,即$ans[L][R]$代表着第$L$块到第$R$块的序列所代表的答案.这个可以$O(n*n/T)$预处理 然后我们先将所有的数给离散化,然后对每一个值都开一个vector,记录这个值在数组中

bzoj2724: [Violet 6]蒲公英(离散化+分块)

我好弱啊..这题调了2天QwQ 题目大意:给定一个长度为n(n<=40000)的序列,m(m<=50000)次询问l~r之间出现次数最多的数.(区间众数) 这题如果用主席树就可以不用处理一堆前缀和..蓝鹅我不会~T_T~. 把序列n分成sqrt(n)块,先把所有数离散化,预处理出poi[i][j]表示第i块到第j块的众数(即出现次数最多的数). 询问有两种情况: 第一种情况是l~r在某个块中,那么直接扫一遍求出众数,效率O(sqrt(n)). 第二种情况是l~r在多个块中,l在x块,r在y块,

【BZOJ2724】[Violet 6]蒲公英 分块+二分

[BZOJ2724][Violet 6]蒲公英 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Output 1 2 1 HINT 修正下: n <= 40000, m <= 50000 题解:分块还是练脑子啊~ 结论:一个区间的众数要么是区间中一个块的众数,要么是块外的任意

【BZOJ 2724】 2724: [Violet 6]蒲公英 (区间众数不带修改版本)

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1908  Solved: 678 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Output 1 2 1 HINT 修正下: n <= 4

BZOJ 2724: [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1633  Solved: 563[Submit][Status][Discuss] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Outp

【BZOJ 2724】 [Violet 6]蒲公英

2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MB Submit: 970  Solved: 319 [Submit][Status][Discuss] Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 Output Sample Input 6 3 1 2 3 2 1 2 1 5 3 6 1 5 Sample Out

「Violet」蒲公英

「Violet」蒲公英 传送门 区间众数,强制在线. 分块经典题. 像这题一样预处理,然后就直接爆搞,复杂度 \(O(n \sqrt n)\) 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".ou

【bzoj2724】[Violet 6]蒲公英 分块+STL-vector

题目描述 输入 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n + 1 输出 样例输入 6 3 1 2 3 2 1 2 1 5 3 6 1 5 样例输出 1 2 1 题解 分块+STL-vector 一个显而易见的结论:区间众数一定是一段连续的块的众数或块外的数,证明略(逃 先把数据离散化,然后分块预处理出f[i][j],表示从块i到块j的众数位置.具体实现的话直接开个桶存一下就好了. 然后考虑询问,整块的直接拿出来求一下出现次