luogu P4168 蒲公英
阿新 • • 發佈:2018-12-24
傳送門
題目描述
在鄉下的小路旁種著許多蒲公英,而我們的問題正是與這些蒲公英有關。
為了簡化起見,我們把所有的蒲公英看成一個長度為n的序列\((a_1,a_2..a_n)\),其中 \(a_i\)為一個正整數,表示第i棵蒲公英的種類編號。
而每次詢問一個區間 [l,r],你需要回答區間裡出現次數最多的是哪種蒲公英,如果有若干種蒲公英出現次數相同,則輸出種類編號最小的那個。
注意,你的演算法必須是線上的
Solution
分塊
但是要維護些什麼呢?
假設我們已經對原序列進行了分塊,對於一個詢問\([l,r]\),我們所尋求的答案很大概率出現在中間的完整的塊中,否則,它就一定在兩邊離散的數中出現過,而這些數是不超過\(2 \sqrt n\)
的。
所以,我們只要維護一個 \(ans[i][j]\)表示第i塊到第j塊的答案,這個初始化時\(O(n \sqrt n)\)的。
還有就是每個數的出現次數,\(num[x][i]\)表示數x在前i塊出現的次數
不過,如果打得不夠優美的話是要TLE的。。。
Code
#include<bits/stdc++.h> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } #define MN 40005 int N,M,col[MN],fcol[MN],tt[MN],tot; int T,pos[MN],a[205][205],num[MN][205],L[MN],R[MN]; inline void init() { register int i,j; std::sort(tt+1,tt+tot+1); tot=std::unique(tt+1,tt+tot+1)-tt-1; for(i=1;i<=N;++i) { int p=col[i]; col[i]=std::lower_bound(tt+1,tt+tot+1,col[i])-tt; fcol[col[i]]=p; } for(i=N;i>=1;--i) { if(pos[i]==pos[i-1]) continue; L[pos[i]]=i; register int ans=0,bl=pos[i]; for(j=i;j<=N;++j) { num[col[j]][bl]++; if(num[col[j]][bl]>num[ans][bl]) ans=col[j]; if(num[col[j]][bl]==num[ans][bl]&&col[j]<ans) ans=col[j]; if(pos[j]!=pos[j+1]) R[pos[j]]=j,a[pos[i]][pos[j]]=ans; } } memset(num,0,sizeof num); for(i=1;i<=N;++i) { num[col[i]][pos[i]]++; if(pos[i]!=pos[i+1]&&i!=N) for(j=1;j<=tot;++j) num[j][pos[i]+1]=num[j][pos[i]]; } } int tmp[MN]; bool vis[MN]; inline int query(int l,int r) { memset(tmp,0,sizeof tmp); memset(vis,0,sizeof vis); register int i,ll,rr,ans=0; ll=pos[l]+(l!=L[pos[l]]); rr=pos[r]-(r!=R[pos[r]]); if(l!=L[pos[l]]) for(i=l;i<=R[pos[l]];++i) { tmp[col[i]]++; if(!vis[col[i]]) vis[col[i]]=true,tmp[col[i]]+=num[col[i]][rr]-num[col[i]][ll-1]; if(tmp[col[i]]>tmp[ans]||(tmp[ans]==tmp[col[i]]&&col[i]<ans)) ans=col[i]; } if(r!=R[pos[r]]) for(i=L[pos[r]];i<=r;++i) { tmp[col[i]]++; if(!vis[col[i]]) vis[col[i]]=true,tmp[col[i]]+=num[col[i]][rr]-num[col[i]][ll-1]; if(tmp[col[i]]>tmp[ans]||(tmp[ans]==tmp[col[i]]&&col[i]<ans)) ans=col[i]; } register int o=a[ll][rr],numo=num[o][rr]-num[o][ll-1]; // printf("ll=%d rr=%d o=%d\n",ll,rr,o); if(!vis[o]&&(numo>tmp[ans]||(numo==tmp[ans]&&o<ans))) ans=o; return fcol[ans]; } int main() { // freopen("testdata.in","r",stdin); // freopen("tesedata.out","w",stdout); N=read();M=read(); register int i;T=(int)(sqrt(N)); for(i=1;i<=N;++i) col[i]=read(),pos[i]=(i-1)/T+1,tt[++tot]=col[i]; init(); int l,r,x=0; // L=(l0-1+x) mod n +1,R = (r0-1 + x ) mod n +1 while(M--) { l=read();r=read(); l=(l-1+x)%N+1,r=(r-1+x)%N+1; if(l>r) std::swap(l,r); // printf("%d %d\n",l,r); x=query(l,r); printf("%d\n",x); } return 0; }
Blog來自PaperCloud,未經允許,請勿轉載,TKS!