Loj 6499 颜色

分块 + bitset + ST 表.

对序列分块,用 bitset 来合并这些区间.

每一块开一个 bitset ,每次合并两个块需要 $O(\frac n w)$ 的时间,比边角部分的暴力处理劣,需要优化.

数字种类是可重复贡献的,可以用 ST 表来快速合并多个块,即设 $f(i,j)$ 表示 $[i,i+2^j-1]$ 这些块合并后的 bitset .

记块大小为 $S$ ,预处理 ST 表的时间复杂度为 $O(\frac{n^2}{Sw}\log \frac{n}{S})$ ,单次询问的时间复杂度为 $O(S+\frac{n}{w})$ .

空间复杂度为 $O(\frac{n^2}{Sw} \log \frac n S)$ .

时间和空间限制都比较紧,可以手写 bitset ,并把 $S$ 设置得稍大一点.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//%std
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=1e5+10,S=1400,T=73,K=9;
int n,m,p,a[MAXN],b[MAXN],cnt;
struct Bitset
{
unsigned int s[MAXN/32+2];
void set(unsigned int x)
{
s[x>>5]|=1u<<(x&31);
}
int count()
{
int ans=0;
for(int i=0;i<=cnt;++i)
ans+=__builtin_popcount(s[i]);
return ans;
}
void clear()
{
memset(s,0,sizeof s);
}
}f[T][K],ans,tmp;
Bitset merge(const Bitset &A,const Bitset &B)
{
for(int i=0;i<=cnt;++i)
tmp.s[i]=A.s[i]|B.s[i];
return tmp;
}
int Log[T],tot,bel[MAXN],lp[T],rp[T],lastans=-1;
void init()
{
for(int i=1;i<=n;++i)
{
bel[i]=(i-1)/S+1;
lp[bel[i]]=(bel[i]-1)*S+1;
rp[bel[i]]=bel[i]*S;
f[bel[i]][0].set(a[i]);
}
rp[bel[n]]=n,tot=bel[n];
Log[1]=0;
for(int i=2;i<=tot;++i)
Log[i]=Log[i>>1]+1;
for(int j=1;j<=Log[tot];++j)
for(int i=1;i+(1<<j)-1<=tot;++i)
f[i][j]=merge(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
void query(int L,int R)
{
if(bel[L]+1>bel[R]-1)
{
for(int i=L;i<=R;++i)
ans.set(a[i]);
}
else
{
for(int i=L;i<=rp[bel[L]];++i)
ans.set(a[i]);
int l=bel[L]+1,r=bel[R]-1,k=Log[r-l+1];
ans=merge(ans,f[l][k]);
ans=merge(ans,f[r-(1<<k)+1][k]);
for(int i=lp[bel[R]];i<=R;++i)
ans.set(a[i]);
}
}
int main()
{
n=read(),m=read(),p=read();
for(int i=1;i<=n;++i)
a[i]=b[i]=read();
sort(b+1,b+1+n);
cnt=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;++i)
a[i]=lower_bound(b+1,b+1+cnt,a[i])-b-1;
cnt=(cnt-1)>>5;
init();
for(int i=1;i<=m;++i)
{
ans.clear();
int k=read();
for(int j=1;j<=k;++j)
{
int L=read(),R=read();
if(p && lastans!=-1)
{
L=(L^lastans)%n+1;
R=(R^lastans)%n+1;
if(L>R)
swap(L,R);
}
query(L,R);
}
printf("%d\n",lastans=ans.count());
}
return 0;
}