题目
思路
首先,我想到了莫队。
排序+分块后,查询的时间被打乱了。
对于值的修改,该怎么办呢?这时候我们就使用带修莫队。带修莫队和普通莫队思路基本上是一样的,只是加入了一条时间轴。记录当前状态的时间,当转移到下一个状态时,如果当前时间小于下一时间,那么就减去现在的,换为并加上之前记录的;反正进行回退,并记录这一时间的状态为Pre,方便之后的回退。
详见代码
Code:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 133335
#define MAXM 1000005
#define LL long long
#define Int register int
using namespace std;
inline void read(int &x)
{
x = 0;
int f = 1;
char s = getchar();
while (s < '0' || s > '9')
{
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9')
{
x = (x << 3) + (x << 1) + (s ^ 48);
s = getchar();
}
x *= f;
}
struct node
{
int l, r, Time, Index;
}As[MAXN];
int Kuai;
bool cmp(node x,node y)
{
if (x.l / Kuai != y.l / Kuai)
return x.l < y.l;
if (x.r / Kuai != y.r / Kuai)
return x.r < y.r;
return x.Time < y.Time;
}
int a[MAXN], totQ, totR, Pre[MAXN];
struct edon
{
int Ct, pos, val;
}Ch[MAXN];
int Curl = 1, Curr, Ans[MAXN], cnt[MAXM], Kind, R_Index;
void Huan_a(int Ti)
{
if (Ch[Ti].pos >= Curl && Ch[Ti].pos <= Curr)
{
cnt[a[Ch[Ti].pos]] --;
if (! cnt[a[Ch[Ti].pos]])
Kind --;
}
Pre[Ti] = a[Ch[Ti].pos];
a[Ch[Ti].pos] = Ch[Ti].val;
if (Ch[Ti].pos >= Curl && Ch[Ti].pos <= Curr)
{
if (! cnt[a[Ch[Ti].pos]])
Kind ++;
cnt[a[Ch[Ti].pos]] ++;
}
}
void Huan_n(int Ti)
{
if (Ch[Ti].pos >= Curl && Ch[Ti].pos <= Curr)
{
cnt[a[Ch[Ti].pos]] --;
if (! cnt[a[Ch[Ti].pos]])
Kind --;
}
a[Ch[Ti].pos] = Pre[Ti];
if (Ch[Ti].pos >= Curl && Ch[Ti].pos <= Curr)
{
if (! cnt[a[Ch[Ti].pos]])
Kind ++;
cnt[a[Ch[Ti].pos]] ++;
}
}
void Change(int Ti)
{
while (R_Index < totR && Ch[R_Index + 1].Ct <= Ti)
Huan_a(++ R_Index);
while (R_Index && Ch[R_Index].Ct > Ti)
Huan_n(R_Index --);
}
void Jia(int x)
{
int X = a[x];
if (! cnt[X])
Kind ++;
cnt[X] ++;
}
void Jian(int x)
{
int X = a[x];
cnt[X] --;
if (! cnt[X])
Kind --;
}
int main()
{
//freopen("fuckk.in","r",stdin);
//freopen("sad.out","w",stdout);
int n, m;
read( n ); read( m );
for (Int i = 1; i <= n; ++ i)
read( a[i] );
for (Int i = 1; i <= m; ++ i)
{
char Or[2];
scanf("%s", Or);
if (Or[0] == 'Q')
{
totQ ++;
As[totQ].Index = totQ;
As[totQ].Time = i;
read( As[totQ].l );
read( As[totQ].r );
}
else
{
totR ++;
Ch[totR].Ct = i;
read( Ch[totR].pos );
read( Ch[totR].val );
}
}
Kuai = pow(n * n, 0.33333);
sort(As + 1, As + 1 + totQ, cmp);
for (Int i = 1; i <= totQ; ++ i)
{
Change( As[i].Time );
int L = As[i].l, R = As[i].r;
while (Curl < L)
Jian(Curl ++);
while (Curl > L)
Jia(-- Curl);
while (Curr < R)
Jia(++ Curr);
while (Curr > R)
Jian(Curr --);
int ind = As[i].Index;
Ans[ind] = Kind;
}
for (Int i = 1; i <= totQ; ++ i)
printf("%d\n", Ans[i]);
return 0;
}
然而,随着这份优秀的代码在bzoj上可以过,在修改数据后的洛谷上是过不了的。这个时候,我们就需要使用树套树了。详见另一份树套树题解。
—————— 坑 ——————— 还没写。。