Description
小X,作为一只死宅,又攒了好多新番要补。
然而由于他的大多数时间都被用来学OI(推galgame)了,他补番的方案要精打细算。
于是他把所有要补的番排成一个长度为\(n\)序列,利用这个序列优化他的方案。
具体说,序列中的每部番都有一个特征值\(a_i\)。
而由于他每天的心情不同,想看番的期望值\(k\)也不同。
每次,他会选择一个区间\([l,r]\),然后把这个区间内特征值\(a_i\)和他的期望值\(k\)相同的番都补一集。
他想知道这次操作要补多少集番,来预估自己晚上有没有时间睡觉。
当然,由于某些特殊的影响,小X会放弃某个番剧\(i\),并将其替换,于是他会把\(a_i\)的值修改为\(x\)。
对于小X的每次询问操作,你都需要输出他补多少集番。
Input
第一行两个整数\(n,m\),表示序列长度和操作次数。
第二行\(n\)个整数\(a_1\)-\(a_n\),表示初始序列。
接下来\(m\)行,每行一个整数\(o\),表示操作类型。
如果\(o = 1\),表示这是一个询问操作,接下来三个整数\(l,r,k\),表示小X补番的区间和期望的特征值\(k\)。
如果\(o = 2\),表示这是一个修改操作,接下来两个整数\(p,x\),表示小X将序列第\(p\)项替换为特征值为\(x\)的番剧。
强制在线,\(l\),\(r\)和\(p\)都要加上上一次的答案\(lastans\)并对\(n\)取模并\(+1\),如果取模后\(l>r\),请自行交换\(l,r\)。
Output
对于每个询问操作,输出一个整数\(ans_i\),表示小X补番的数量。
Hint
对于\(100\%\)的数据,\(n,m\leq 7\times 10^5\)。
所有特征值\(a_i\)均不超过\(MAX_{}INT\)且非负。
时间限制\(3s\),空间限制\(40MB\)。
Source
Cmd2001
Solution
乍一看是 \(7e5\) 的强制在线数颜色,但是询问的是特定值的个数。
所以考虑对于每个特征值维护一棵平衡树。
对于每个特征值我们用一棵 \(fhq_{}Treap\) 维护有哪些位置有这个特征值。
\(1\) 操作,可以把这棵树上 \(split\) 出 \([l,r]\) 这段区间,然后求根节点的 \(size\) 就好。
\(2\) 操作,先在这个位置原来的特征值中的 \(Treap\) 中删掉这个位置,然后将新的特征值的 \(Treap\) 里插入当前位置即可。
水题水题~
那你还打40分暴力
Code
#include<map>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#define min(A,B) (A)<(B)?(A):(B)
#define max(A,B) (A)>(B)?(A):(B)
#define N 700005+1005
#define inf 0x3f3f3f3f
int n,m;
int a[N];
int cur,cnt;
int del_cur;
int root[N];
int delpool[1005];
int prio[N],val[N];
int sze[N],ch[N][2];
std::map<int,int> mp;
int newnode(){
if(del_cur) return delpool[del_cur--];
return ++cur;
}
void read(int &x){
x=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
}
void write(int x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
void pushup(int now){
sze[now]=sze[ch[now][0]]+sze[ch[now][1]]+1;
}
void split(int now,int k,int &x,int &y){
if(!now) x=y=0;
else{
if(val[now]<k){
x=now;
split(ch[now][1],k,ch[now][1],y);
}
else{
y=now;
split(ch[now][0],k,x,ch[now][0]);
}
pushup(now);
}
}
int merge(int x,int y){
if(!x or !y) return x+y;
if(prio[x]<prio[y]){
ch[x][1]=merge(ch[x][1],y);
pushup(x);
return x;
}
ch[y][0]=merge(x,ch[y][0]);
pushup(y);
return y;
}
int new_node(int b){
int now=newnode();
sze[now]=1;
val[now]=b;
prio[now]=rand();
ch[now][0]=ch[now][1]=0;
return now;
}
void insert(int c,int b){
int x,y;
split(root[c],b,x,y);
root[c]=merge(x,merge(new_node(b),y));
}
int query(int e,int b,int c){
int x,y,z,d;
split(root[c],e,x,y);
split(y,b+1,y,z);
int k=sze[y];
root[c]=merge(x,merge(y,z));
return k;
}
void remove(int c,int b){
int x,y,z;
split(root[c],b,x,y);
split(y,b+1,y,z);
root[c]=merge(x,z);
delpool[++del_cur]=y;
}
signed main(){
srand(2002+01+22);
read(n),read(m);
for(int x,i=1;i<=n;i++){
read(x); a[i]=x;
if(!mp[x]) mp[x]=++cnt;
insert(mp[x],i);
}
int last=0;
while(m--){
int o,l,r,k;
read(o);
if(o==1){
read(l),read(r),read(k);
l=(l+last)%n+1;
r=(r+last)%n+1;
if(l>r) l^=r^=l^=r;
last=query(l,r,mp[k]);
write(last); putchar('\n');
}
else{
read(l),read(r);
l=(l+last)%n+1;
if(!mp[r]) mp[r]=++cnt;
remove(mp[a[l]],l);
a[l]=r;
insert(mp[r],l);
}
}
return 0;
}