题目链接:点击这里
题目大意:
给定一个长度为
n
n
n 的序列
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an
序列支持两种操作:
- 询问你 [ l , r ] [l,r] [l,r] 中共有几种不同的数字
- 将一个位置的数字替换成另一个数字
题目分析:
莫队加上了修改操作只需在之前的莫队版本上加一个时间戳就可以了
其排序有了些许变化(就是莫队多了一维):
struct query{
int l,r,t,id;
friend bool operator < (const query &a,const query &b)
{
return a.l/block^b.l/block ? a.l < b.l : a.r/block^b.r/block ? a.r<b.r : a.t < b.t;
}
};
改时间轴的一个小优化:
移完
t
t
t ,时间轴还有可能会移回来,所以我们每次修改时交换一下修改后的值和原值,等时间轴移回来时再交换回来就可以了
块的大小:
块大小取
n
\sqrt n
n 时,有可能使程序的时间复杂度退化为
O
(
n
2
)
O(n^2)
O(n2) ,这里我们把块大小取
n
2
3
n^{\frac 2 3}
n32 ,此时时间复杂度为
O
(
n
3
5
)
O(n^{\frac 35})
O(n53)
证明:
块大小为
n
2
3
n^{\frac23}
n32 ,所以有
n
1
3
n^{\frac 13}
n31 个块
左右端点在一个块时,时间在排序后单调递增,这样的复杂度是
O
(
n
)
O(n)
O(n)
左右端点不在一个块时,时间一次最多会移动
n
n
n 个格子,时间复杂度
O
(
n
)
O(n)
O(n)
左端点所在块一共有
n
1
3
n^{\frac{1}{3}}
n31 种,右端点也是
n
1
3
n^{\frac{1}{3}}
n31 种,一共有
n
2
3
n^\frac{2}{3}
n32 种,每种乘上移动的复杂度
O
(
n
)
O(n)
O(n) ,所以总复杂度为
O
(
n
5
3
)
O(n^{\frac{5}{3}})
O(n35)
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 2e5+5;
const int maxm = 1e6;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,m,now,tim,block,cntq,cntc,a[maxn],cnt[maxm],ans[maxn];
struct query{
int l,r,t,id;
friend bool operator < (const query &a,const query &b)
{
return a.l/block^b.l/block ? a.l < b.l : a.r/block^b.r/block ? a.r<b.r : a.t < b.t;
}
}q[maxn];
struct updat{
int pos,val;
}c[maxn];
char s[15];
int main()
{
n = read(),m = read();
block = pow(n,2.0/3.0);
for(int i = 1;i <= n;i++)
a[i] = read();
for(int i = 1;i <= m;i++)
{
scanf("%s",s);
if(s[0] == 'Q')
{
q[++cntq].l = read();
q[cntq].r = read();
q[cntq].id = cntq;
q[cntq].t = cntc;
}
else {
c[++cntc].pos = read();
c[cntc].val = read();
}
}
sort(q+1,q+cntq+1);
int l = 1,r = 0;
for(int i = 1;i <= cntq;i++)
{
int ql = q[i].l,qr = q[i].r;
while(l < ql) now -= !--cnt[a[l++]];
while(l > ql) now += !cnt[a[--l]]++;
while(r < qr) now += !cnt[a[++r]]++;
while(r > qr) now -= !--cnt[a[r--]];
while(tim < q[i].t)
{
tim++;
if(ql<=c[tim].pos && qr>=c[tim].pos)
now -= !--cnt[a[c[tim].pos]]-!cnt[c[tim].val]++;
swap(a[c[tim].pos],c[tim].val);
}
while(tim > q[i].t)
{
if(ql<=c[tim].pos && qr>=c[tim].pos)
now -= !--cnt[a[c[tim].pos]]-!cnt[c[tim].val]++;
swap(a[c[tim].pos],c[tim].val);
tim--;
}
ans[q[i].id] = now;
}
for(int i = 1;i <= cntq;i++)
printf("%d\n",ans[i]);
return 0;
}