bzoj2724 [Violet 6]蒲公英
2724: [Violet 6]蒲公英
Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 2706 Solved: 950
[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
1 2 3 2 1 2
1 5
3 6
1 5
Sample Output
1
2
1
2
1
HINT
n <= 40000, m <= 50000
Source
分析:经典题.
如果没有强制在线,就可以用莫队算法解决了. 能够利用莫队算法这一事实提供了一个思路:根号算法.
还有哪些根号算法呢?可以分块!首先有一个结论:区间[l,r]的众数一定是[l,r]整块的众数或者是不在整块的数. 一个想法就是预处理出f数组,f[i][j]表示第i块到第j块的众数. 枚举左端点,维护一个桶就能够预处理出来了.
怎么求区间[l,r]出现了多少次a呢? 前缀和?空间不够. 一个可行的方法是对块进行前缀和,然后枚举不在整块内的元素,用一个桶维护每个值出现的次数. 有一个更好的方法:开一个vector数组,第i个vector存着权值为i的下标. 每次upper_bound,lower_bound找下标正好在[l,r]的个数就好了.
#include <vector> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const ll maxn = 50010; ll n,m,a[maxn],b[maxn],tot[maxn],cnt,cntt,lastans; ll pos[maxn],L[maxn],R[maxn],block,f[1010][1010]; vector <ll>e[maxn]; void pre(ll x) { ll ans = 0,tott = 0; memset(tot,0,sizeof(tot)); for (ll i = L[x]; i <= n; i++) { tot[a[i]]++; if (tot[a[i]] > tott || (tot[a[i]] == tott && b[ans] > b[a[i]])) { ans = a[i]; tott = tot[a[i]]; } f[x][pos[i]] = ans; } } ll query(ll l,ll r) { if (pos[l] == pos[r]) { ll ans = 0; cntt = 0; for (ll i = l; i <= r; i++) { ll temp = upper_bound(e[a[i]].begin(),e[a[i]].end(),r) - lower_bound(e[a[i]].begin(),e[a[i]].end(),l); if (temp > cntt || (temp == cntt && b[a[i]] < b[ans])) { ans = a[i]; cntt = temp; } } return ans; } ll temp = f[pos[l] + 1][pos[r] - 1]; ll cntt = upper_bound(e[temp].begin(),e[temp].end(),r) - lower_bound(e[temp].begin(),e[temp].end(),l); for (ll i = l; i <= R[pos[l]]; i++) { ll tmp = upper_bound(e[a[i]].begin(),e[a[i]].end(),r) - lower_bound(e[a[i]].begin(),e[a[i]].end(),l); if (tmp > cntt || (tmp == cntt && a[i] < temp)) { temp = a[i]; cntt = tmp; } } for (ll i = L[pos[r]]; i <= r; i++) { ll tmp = upper_bound(e[a[i]].begin(),e[a[i]].end(),r) - lower_bound(e[a[i]].begin(),e[a[i]].end(),l); if (tmp > cntt || (tmp == cntt && a[i] < temp)) { temp = a[i]; cntt = tmp; } } return temp; } int main() { scanf("%lld%lld",&n,&m); block = sqrt(n); for (ll i = 1; i <= n; i++) { scanf("%lld",&a[i]); b[i] = a[i]; pos[i] = (i - 1) / block + 1; } cnt = (n - 1) / block + 1; for (ll i = 1; i <= cnt; i++) { L[i] = R[i - 1] + 1; R[i] = min(i * block,n); } sort(b + 1,b + 1 + n); cntt = unique(b + 1,b + 1 + n) - b - 1; for (ll i = 1; i <= n; i++) a[i] = lower_bound(b + 1,b + 1 + cntt,a[i]) - b; for (ll i = 1; i <= n; i++) e[a[i]].push_back(i); for (ll i = 1; i <= n; i++) sort(e[i].begin(),e[i].end()); for (ll i = 1; i <= cnt; i++) pre(i); for (ll i = 1; i <= m; i++) { ll l,r; scanf("%lld%lld",&l,&r); l = (l + lastans - 1) % n + 1; r = (r + lastans - 1) % n + 1; if (l > r) swap(l,r); printf("%lld\n",lastans = b[query(l,r)]); } return 0; }