1. 程式人生 > >[BZOJ2724][Violet 6]蒲公英(分塊)

[BZOJ2724][Violet 6]蒲公英(分塊)

題目描述

傳送門

題解

預處理一坨。
塊外暴力。
塊內sort(關鍵字先權值再位置),然後二分找。

程式碼

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
using namespace std;

const int max_n=4e4+5;
const int max_t=2e2+5;

int n,m,cnt,t1,t2,l,r;
int
a[max_n],b[max_n],c[max_n],mp[max_n],num[max_n]; int last[max_t]; struct hp{ int val,num; }aa[max_n]; struct hq{ int l,r; }k[max_n]; int val[max_n],number[max_n]; int ans,ansk; int key[max_t][max_t],sum[max_t][max_t],s[max_n]; inline int cmp1(int x,int y){ return b[x]<b[y]; } inline int
cmp(hp a,hp b){ return a.val<b.val||(a.val==b.val&&a.num<b.num); } inline void add(int i,int tot){ s[a[i]]+=tot; if (s[a[i]]>ans){ ans=s[a[i]]; ansk=mp[a[i]]; } else if (s[a[i]]==ans&&ansk>mp[a[i]]) ansk=mp[a[i]]; } inline void Query(int
l,int r){ int lrange,rrange; memset(s,0,sizeof(s)); ans=ansk=0; if (num[l]==num[r]){ for (int i=l;i<=r;++i) add(i,1); printf("%d\n",ansk); return; } if (l!=last[num[l]-1]+1) lrange=num[l]+1; else lrange=num[l]; if (r!=last[num[r]]) rrange=num[r]-1; else rrange=num[r]; ans=sum[lrange][rrange]; ansk=mp[key[lrange][rrange]]; if (l!=last[num[l]-1]+1) for (int i=l;i<=last[num[l]];++i) if (!s[a[i]]){ add(i,1); int loc1=k[a[i]].l; int loc2=k[a[i]].r; int loc3=lower_bound(number+loc1,number+loc2+1,lrange)-number; if (loc3>loc2) continue; int loc4=upper_bound(number+loc1,number+loc2+1,rrange)-number-1; if (loc3>loc4) continue; int tot=loc4-loc3+1; add(i,tot); } else add(i,1); if (r!=last[num[r]]) for (int i=last[num[r]-1]+1;i<=r;++i) if (!s[a[i]]){ add(i,1); int loc1=k[a[i]].l; int loc2=k[a[i]].r; int loc3=lower_bound(number+loc1,number+loc2+1,lrange)-number; if (loc3>loc2) continue; int loc4=upper_bound(number+loc1,number+loc2+1,rrange)-number-1; if (loc3>loc4) continue; int tot=loc4-loc3+1; add(i,tot); } else add(i,1); printf("%d\n",ansk); } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;++i){ scanf("%d",&b[i]); c[i]=i; } sort(c+1,c+n+1,cmp1); for (int i=1;i<=n;++i) if (b[c[i]]!=b[c[i-1]]) a[c[i]]=++cnt; else a[c[i]]=cnt; for (int i=1;i<=n;++i) mp[a[i]]=b[i]; int t1=(int)sqrt(n); if (n%t1==0) t2=n/t1; else t2=n/t1+1; for (int i=1;i<=n;++i) if (i%t1==0) num[i]=i/t1; else num[i]=i/t1+1; for (int i=1;i<=t2;++i) last[i]=min(i*t1,n); for (int i=1;i<=n;++i){ aa[i].val=a[i]; aa[i].num=num[i]; } sort(aa+1,aa+n+1,cmp); for (int i=1;i<=n;++i){ val[i]=aa[i].val; number[i]=aa[i].num; } k[1].l=1; for (int i=2;i<=n;++i) if (val[i]!=val[i-1]){ k[val[i]].l=i; k[val[i-1]].r=i-1; } k[cnt].r=n; int head=0,tail=0; ans=ansk=0; while (head<=t2){ head++; tail=head; memset(s,0,sizeof(s)); ans=ansk=0; for (int i=last[head-1]+1;i<=last[head];++i){ ++s[a[i]]; if (s[a[i]]>ans){ ans=s[a[i]]; ansk=a[i]; } else if (s[a[i]]==ans&&ansk>a[i]) ansk=a[i]; } key[head][tail]=ansk; sum[head][tail]=ans; while (tail<=t2){ tail++; for (int i=last[tail-1]+1;i<=last[tail];++i){ ++s[a[i]]; if (s[a[i]]>ans){ ans=s[a[i]]; ansk=a[i]; } else if (s[a[i]]==ans&&ansk>a[i]) ansk=a[i]; } key[head][tail]=ansk; sum[head][tail]=ans; } } ans=ansk=0; for (int i=1;i<=m;++i){ scanf("%d%d",&l,&r); l=(l+ansk-1)%n+1; r=(r+ansk-1)%n+1; if (l>r) swap(l,r); Query(l,r); } }

總結

程式碼跑的慢。姿勢太蠢?