[模擬賽] 補番計劃
Description
小X,作為一只死宅,又攢了好多新番要補。
然而由於他的大多數時間都被用來學OI(推galgame)了,他補番的方案要精打細算。
於是他把所有要補的番排成一個長度為\(n\)序列,利用這個序列優化他的方案。
具體說,序列中的每部番都有一個特征值\(a_i\)。
而由於他每天的心情不同,想看番的期望值\(k\)也不同。
每次,他會選擇一個區間\([l,r]\),然後把這個區間內特征值\(a_i\)和他的期望值\(k\)相同的番都補一集。
他想知道這次操作要補多少集番,來預估自己晚上有沒有時間睡覺。
當然,由於某些特殊的影響,小X會放棄某個番劇\(i\),並將其替換,於是他會把\(a_i\)
對於小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\)
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;
}
[模擬賽] 補番計劃