1. 程式人生 > >Loj#6285.數列分塊入門-9-暴力分塊

Loj#6285.數列分塊入門-9-暴力分塊

(有任何問題歡迎留言或私聊 && 歡迎交流討論哦

題目:傳送門

 給出一個長為 n 的數列,以及 n 個詢問,詢問區間[L, R]的最小眾數。

思路:

1.分塊暴力搞:

離散化資料
預處理出每兩個塊間的眾數f[i][j]
預處理每個數出現的位置,放在一個桶裡面。
預處理前k塊中第j個數據的出現次數 cnt[k][j]// 其實這個預處理可以不用,也可以每次upper_bound()-lower_bound()代替

一:對於整塊區間直接O(1)查詢眾數f[belong[a]+1][belong[b]-1],O(1)查詢數量cnt[belong[b]-1][x]-cnt[belong[a]][x]


二:對於旁邊的區間的資料,列舉在查詢區間[a, b]出現的次數。如果次數較大或者資料較小就更新ans。

(頻繁用memset清空1e5的陣列導致跑了6000+ms,改成列舉指定數量快了10倍,577ms左右)

AC程式碼;

//577ms
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<ctime>
#include<vector>
#include<cmath>
#define fuck(x) cout<<"* "<<x<<"\n" using namespace std; typedef long long LL; const int N = 1e5+7; const int INF = 0x3f3f3f3f; int n,belong[N],br[N],now[N],cnt[N],f[500][500],l[N],r[N],block,Num,k; vector<int> g[N]; int ar[N],cw[500][N]; inline void build(){ block=sqrt(n*1.0); Num=n/block;if
(n%block)Num++; for(int i=1;i<=Num;++i){ l[i]=(i-1)*block+1;r[i]=i*block; } r[Num]=n; for(int i=1;i<=n;++i){ belong[i]=(i-1)/block+1; now[i]=lower_bound(br+1,br+1+k,ar[i])-br; cw[belong[i]][now[i]]++; } for(int i=1;i<=n;++i){ g[now[i]].push_back(i); } for(int i=1;i<=Num;++i){ for(int j=1;j<=k;++j){ cw[i][j]+=cw[i-1][j]; } } } inline int get(int a,int b,int x){ if(belong[a]==belong[b]){ return cw[belong[b]][x]-cw[belong[a]][x]; } return cw[belong[b]-1][x]-cw[belong[a]][x]; //return (upper_bound(g[x].begin(),g[x].end(),b)-lower_bound(g[x].begin(),g[x].end(),a)); } inline void chaobaoli(int a,int b){ for(int i=0;i<=k;++i){ cnt[i]=0; } int p=f[belong[a]+1][belong[b]-1]; int num_max=get(a,b,p); int da=min(r[belong[a]],b); for(int i=a;i<=da;++i){ cnt[now[i]]++; int tnum=get(a,b,now[i])+cnt[now[i]]; if(tnum>num_max||(tnum==num_max&&br[p]>br[now[i]])){ p=now[i]; num_max=tnum; } } if(belong[a]!=belong[b]) for(int i=l[belong[b]];i<=b;++i){ cnt[now[i]]++; int tnum=get(a,b,now[i])+cnt[now[i]]; if(tnum>num_max||(tnum==num_max&&br[p]>br[now[i]])){ p=now[i]; num_max=tnum; } } printf("%d\n",br[p] ); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&ar[i]); br[i]=ar[i]; } sort(br+1,br+1+n); k=1; for(int i=2;i<=n;++i){ if(br[i]!=br[i-1]){ br[++k]=br[i]; } } build(); for(int i=1;i<=Num;++i){ for(int i=0;i<=k;++i){ cnt[i]=0; } int num_max=0,p=0; for(int j=l[i];j<=n;++j){ cnt[now[j]]++; if(cnt[now[j]]>num_max||(cnt[now[j]]==num_max&&br[p]>br[now[j]])){ p=now[j];num_max=cnt[now[j]]; } f[i][belong[j]]=p; } } for(int i=0,a,b;i<n;++i){ scanf("%d%d",&a,&b); if(a>b)a^=b^=a^=b; chaobaoli(a,b); } return 0; }

題目描述

給出一個長為 n 的數列,以及 n 個操作,操作涉及詢問區間的最小眾數。
輸入格式
第一行輸入一個數字 n。

第二行輸入 n 個數字,第 i 個數字為 ai,以空格隔開。

接下來輸入 n 行詢問,每行輸入兩個數字 l、r,以空格隔開。

表示查詢位於 [l,r]的數字的眾數。
輸出格式
對於每次詢問,輸出一行一個數字表示答案。
樣例
樣例輸入
4
1 2 2 4
1 2
1 4
2 4
3 4
樣例輸出
1
2
2
2
輸入:
10
1 2 3 4 3 4 5 2 3 4
1 4
2 6
9 10
4 8
1 8
2 10
4 7
3 9
4 8
6 8
輸出:
1
3
3
4
2
3
4
3
4
2