传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3489
思路:
这题网上到处是树套树,我就不多说了。。。
说一下我的做法,考虑分块,假设将序列块的大小为
B
,那么对于一个询问
怎么得到块与块之间前
2B
大小只出现一次的数呢?考虑暴力扫描,从每个块开始向后扫一直扫到序列的末尾,这样如果每次添加一个元素是均摊
O(1)
的,那么复杂度就是
O(n2B)
。
我们暴力扫描,维护一个权值数组,我们再权值分块,每个权值块维护出现一次的数,用一个队列维护,扫描一个块的时候若一个元素出现一次直接加入相应权值块,若已经出现则无视掉,当一个块扫描完了,从大到小扫描权值数组里的队列,把不合法的删掉,直到达到
2B
个就停止。这样对于每个元素至多会被否掉一次,均摊是
O(1)的
。
得到块与块之间的答案后,查询的时候在数组上打标记就可以了,要适当调整块的大小。
常数大的要死。。。速度在bzoj垫底。。。感人至深。。。
复杂度:
O((n+m)n√)
代码:
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 100002
#define lim 350
#define lim1 350
using namespace std;
int n,m,a[N],b[N],ans,l,r;
inline void in(int &x)
{
char c; int sy = 1;
while (!isdigit(c = getchar()))
if (c == '-') sy = -1;
x = (c ^ 48);
while (isdigit(c = getchar())) x = 10 * x + (c ^ 48);
x *= sy;
}
inline void init()
{
in(n); in(m);
for (int i = 1;i <= n; ++i)
in(a[i]);
for (int i = 1;i <= n; ++i) b[i] = a[i];
sort(b + 1,b + n + 1);
b[0] = unique(b + 1,b + n + 1) - b - 1;
for (int i = 1;i <= n; ++i)
a[i] = lower_bound(b + 1,b + b[0] + 1,a[i]) - b;
}
int B,B1,S[lim1][N],c[N],belong[N],belong1[N],lb[N],rb[N],f[lim1][lim1][lim << 1],use[lim << 1][lim << 1];
inline void Divide()
{
B = (int)(sqrt(n) * 1.1);
belong[0] = belong[n + 1] = -1;
for (int i = 1;i <= n; ++i)
belong[i] = (i - 1) / B + 1;
for (int i = 1;i <= n; ++i)
{
if (belong[i] != belong[i - 1]) lb[belong[i]] = i;
if (belong[i] != belong[i + 1]) rb[belong[i]] = i;
}
int t = b[0];
B1 = (int)(sqrt(b[0]) * 1.6);
belong1[0] = belong1[t + 1] = -1;
for (int i = 1;i <= t; ++i)
belong1[i] = (i - 1) / B1 + 1;
}
int num,num1,ned;
inline void Deal(int s)
{
for (int i = 1;i <= num1; ++i)
use[i][0] = 0;
ned = (int)(B * 1.2);
memset(S[0],0,sizeof(S[0]));
for (int i = s;i <= num; ++i)
{
for (int j = lb[i];j <= rb[i]; ++j)
{
c[a[j]]++;
if (c[a[j]] == 1)
{
int t = belong1[a[j]];
use[t][++use[t][0]] = a[j];
}
}
int t;
f[s][i][0] = 0;
for (int j = num1;j;--j)
{
t = 0;
for (int k = 1;k <= use[j][0]; ++k)
if (c[use[j][k]] == 1)
{
f[s][i][++f[s][i][0]] = use[j][k];
use[j][++t] = use[j][k];
}
use[j][0] = t;
if (f[s][i][0] >= ned) break;
}
if (s == 1)
for (int j = 1;j <= b[0]; ++j)
S[i][j] = c[j];
}
for (int i = lb[s];i <= n; ++i) c[a[i]]--;
}
inline void Prepare()
{
memset(c,0,sizeof(c));
memset(f,0,sizeof(f));
Divide();
num = belong[n]; num1 = belong1[b[0]];
for (int i = 1;i <= num; ++i)
Deal(i);
}
int Q[N];
inline int Get_query()
{
int t1,t2;
int cut = 0;
t1 = belong[l] + 1;t2 = belong[r] - 1;
Q[0] = 0;
if (t1 > t2)
for (int i = l;i <= r; ++i)
{
Q[++Q[0]] = a[i];
cut = Q[0];
}
else
{
int ll = rb[belong[l]],rr = lb[belong[r]];
for (int i = l;i <= ll; ++i)
Q[++Q[0]] = a[i];
for (int i = rr;i <= r; ++i)
Q[++Q[0]] = a[i];
cut = Q[0];
for (int i = 1;i <= f[t1][t2][0]; ++i)
Q[++Q[0]] = f[t1][t2][i];
}
ans = 0;
for (int i = 1;i <= cut; ++i)
c[Q[i]]++;
for (int i = 1;i <= Q[0]; ++i)
{
int s = c[Q[i]];
if (t1 <= t2) s += S[t2][Q[i]] - S[t1 - 1][Q[i]];
if (s == 1) ans = max(ans,b[Q[i]]);
}
for (int i = 1;i <= cut; ++i)
c[Q[i]]--;
}
inline void QUERY()
{
int x,y;
ans = 0;
for (int i = 1;i <= m; ++i)
{
in(x); in(y);
l = (x + ans) % n + 1; r = (y + ans) % n + 1;
if (l > r) swap(l,r);
Get_query();
printf("%d\n",ans);
}
}
inline void DO_IT()
{
Prepare();
QUERY();
}
int main()
{
//freopen("bzoj3489.in","r",stdin);
//freopen("1.out","w",stdout);
init();
DO_IT();
fclose(stdin); fclose(stdout);
return 0;
}