前言
找不到在哪里提交只能口胡了。
题目
找到了!
还有一道类似的
[Ynoi2019 模拟赛] Yuno loves sqrt technology III(洛谷)
题目描述
( exttt{OneInDark}) 有一个长度为 (n) 的序列 (a)。
这一天他找到了你,由于他很喜欢热闹,所以他想询问区间内的众数是什么。
他很专一,所以如果有多个答案,只需要输出编号最小的即可。
而且他喜欢一问一答的交互方式,所以这道题是强制在线。
因为他很强,所以他早就算出了答案,只是需要你与他对一下答案而已。
他有时候也喜欢整蛊,所以他需要你在 (2s) 内算出答案,不然会遭到惩罚。
数据范围
( exttt{OneInDark}) 还是很善解人意的,所以他不会让你很累。
(nle 4*10^4,mle 5*10^4,a_ile 10^9)
讲解
首先我们可以离散化。
考虑分块。
我们可以先用 (O(nsqrt{n})) 的时间复杂度预处理出任意两个块之间形成的区间的众数,以及其出现次数。
我们令 (f[l][r]) 表示 块(l) 到 块(r) 的众数。
对于每个询问,我们考虑答案只可能是这两种情况:
-
在大块中。
-
在零散小块中。
对于第一种情况,答案就是 (f[l][r])。
对于第二种情况,我们考虑零散的数只有 (sqrt{n}) 级别个。
对于每个数,我们记录一下它们出现的位置(预处理)。
然后我们对于零散的数可以二分出其在区间内的出现次数。
时间复杂度为 (O(msqrt{n}logn))。 好像已经可以过了
考虑优化。
我们令 (pos[i][j]) 表示 (i) 在数列中第 (j) 次出现的位置。
令 (t[i]) 表示 (a[i]) 在数列中是第几次出现。
显然我们枚举的零散的数的时候,我们可以将其当做第一次出现。
此时我们需要一个计数的变量 (MAX),其初值为 (f[l][r])。
如果当前枚举的这个数 (a[i]),满足 (pos[a[i]][MAX] le qr) (qr为询问区间的右端点)。
那么我们可以继续向右扩展,显然 (MAX) 总共最多只会扩展 (sqrt{n}) 级别次。
(n,m) 基本同阶,所以总时间复杂度为 (O(nsqrt{n}))。
代码
蒲公英
//12252024832524
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 40005;
const int MAXB = 205;
int n,m,lshtot,ans,B;
int to[MAXN];
struct node
{
int val,lsh,ID;
}s[MAXN];
bool cmp1(node x,node y){return x.val < y.val;}
bool cmp2(node x,node y){return x.ID < y.ID;}
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x);
if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int f[MAXB][MAXB],cs[MAXB][MAXB],bl[MAXN];
int cnt[MAXN],t[MAXN];
vector<int> pos[MAXN];
void pre()
{
for(int i = 1;i <= lshtot;++ i) pos[i].push_back(0);
for(int i = 1;i <= n;++ i) pos[s[i].lsh].push_back(i),t[i] = pos[s[i].lsh].size()-1;
for(int i = 1;i <= n;i += B)
{
int zs = n+1;//众数
for(int j = i;j <= n;++ j)
{
int val = s[j].lsh;
cnt[val]++;
if(cnt[val] > cnt[zs] || (cnt[val] == cnt[zs] && val < zs)) zs = val;
if(bl[j] != bl[j+1]) f[bl[i]][bl[j]] = zs,cs[bl[i]][bl[j]] = cnt[zs];
}
for(int j = i;j <= n;++ j) cnt[s[j].lsh] = 0;
if(i == 1) i--;
}
}
int spsolve(int l,int r)
{
int ret = 0;
for(int i = l;i <= r;++ i)
{
int val = s[i].lsh;
cnt[val]++;
if(cnt[val] > cnt[ret] || (cnt[val] == cnt[ret] && val < ret)) ret = val;
}
for(int i = l;i <= r;++ i) cnt[s[i].lsh] = 0;
return ret;
}
int solve(int l,int r)
{
int L = bl[l],R = bl[r],ret = 0;
if(L == R) return spsolve(l,r);
if(bl[l] == bl[l-1]) L++;
if(bl[r] == bl[r+1]) R--;
if(L <= R) ret = f[L][R];
int MAX = cs[L][R];
for(int i = l;bl[i] != L;++ i)
{
int now = t[i],val = s[i].lsh;
while(pos[val].size()-1 >= now + MAX && pos[val][now+MAX] <= r) MAX++,ret = val;
if(pos[val].size()-1 >= now + MAX - 1 && pos[val][now+MAX-1] <= r && val < ret) ret = val;
}
for(int i = (R+1)*B;i <= r;++ i)
{
int now = t[i],val = s[i].lsh;
while(now - MAX > 0 && pos[val][now-MAX] >= l) MAX++,ret = val;
if(now - MAX + 1 > 0 && pos[val][now-MAX+1] >= l && val < ret) ret = val;
}
return ret;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); m = Read();
for(int i = 1;i <= n;++ i) s[i].val = Read(),s[i].ID = i;
sort(s+1,s+n+1,cmp1);
for(int i = 1;i <= n;++ i)
if(s[i].val == s[i-1].val) s[i].lsh = s[i-1].lsh;
else s[i].lsh = ++lshtot,to[lshtot] = s[i].val;
sort(s+1,s+n+1,cmp2);
B = sqrt(n);
for(int i = 1;i <= n;++ i) bl[i] = i / B;
pre();
for(int i = 1;i <= m;++ i)
{
int l = (Read() + ans - 1) % n + 1,r = (Read() + ans - 1) % n + 1;
if(l > r) swap(l,r);
Put(ans = to[solve(l,r)],'
');
}
return 0;
}
Yuno loves sqrt technology III
这种离散化更快哦
//12252024832524
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 500005;
const int MAXB = 710;
int n,m,len,ans,B;
int a[MAXN],b[MAXN];
LL Read()
{
LL x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x);
if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int f[MAXB][MAXB],cs[MAXB][MAXB],bl[MAXN];
int cnt[MAXN],t[MAXN];
vector<int> pos[MAXN];
void pre()
{
for(int i = 1;i <= len;++ i) pos[i].push_back(0);
for(int i = 1;i <= n;++ i) pos[a[i]].push_back(i),t[i] = pos[a[i]].size()-1;
for(int i = 1;i <= n;i += B)
{
int zs = n+1;//众数
for(int j = i;j <= n;++ j)
{
int val = a[j];
cnt[val]++;
if(cnt[val] > cnt[zs] || (cnt[val] == cnt[zs] && val < zs)) zs = val;
if(bl[j] != bl[j+1]) f[bl[i]][bl[j]] = zs,cs[bl[i]][bl[j]] = cnt[zs];
}
for(int j = i;j <= n;++ j) cnt[a[j]] = 0;
if(i == 1) i--;
}
}
int spsolve(int l,int r)
{
int ret = 0;
for(int i = l;i <= r;++ i)
{
int val = a[i];
cnt[val]++;
if(cnt[val] > cnt[ret] || (cnt[val] == cnt[ret] && val < ret)) ret = val;
}
ret = cnt[ret];
for(int i = l;i <= r;++ i) cnt[a[i]] = 0;
return ret;
}
int solve(int l,int r)
{
int L = bl[l],R = bl[r];
if(L == R) return spsolve(l,r);
if(bl[l] == bl[l-1]) L++;
if(bl[r] == bl[r+1]) R--;
int MAX = cs[L][R];
for(int i = l;bl[i] != L;++ i)
{
int now = t[i],val = a[i];
while(pos[val].size()-1 >= now + MAX && pos[val][now+MAX] <= r) MAX++;
}
for(int i = (R+1)*B;i <= r;++ i)
{
int now = t[i],val = a[i];
while(now - MAX > 0 && pos[val][now-MAX] >= l) MAX++;
}
return MAX;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = Read(); m = Read();
for(int i = 1;i <= n;++ i) a[i] = b[i] = Read()+1;
sort(b+1,b+n+1);
len = unique(b+1,b+n+1)-b;
for(int i = 1;i <= n;++ i) a[i] = lower_bound(b+1,b+len+1,a[i])-b;
B = sqrt(n);
for(int i = 1;i <= n;++ i) bl[i] = i / B;
pre();
for(int i = 1;i <= m;++ i)
{
int l = Read() ^ ans,r = Read() ^ ans;
if(l > r) swap(l,r);
Put(ans = solve(l,r),'
');
}
return 0;
}