您的位置:首页 > 其它

[BZOJ 2120]数颜色:带修改莫队

2017-04-08 16:13 381 查看
点击这里查看原题

与普通莫队相比,本题需要单点修改,因此需要分别记录查询和修改两种操作。

修改操作需要记录:

pos:修改的位置

x:修改前的值

查询操作需要记录:

p:上一个修改操作的序号

id:在输入数据中的顺序

l,r:查询的区间

查询操作依然是按块排序,只不过每次查询时要处理好修改操作。

用一个vis数组记录该位置是否在目前的区间内,如果要修改一个在队中的位置,需要先出队,然后修改该位置的值,再入队。如果不在队中直接修改即可。

/*
User:Small
Language:C++
Problem No.:2120
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=1e4+5;
int n,m,a[M],num[M*100],res,tot,cnt,pos[M],ans[M],b[M];
bool vis[M];
struct op1{
int pos,x,y;
}ch[M];
struct op2{
int pre,l,r,id;
}qu[M];
bool cmp(op2 a,op2 b){
return pos[a.l]!=pos[b.l]?pos[a.l]<pos[b.l]:a.r<b.r;
}
void update(int x){
if(vis[x]){
num[a[x]]--;
if(num[a[x]]==0) res--;
}
else{
num[a[x]]++;
if(num[a[x]]==1) res++;
}
vis[x]^=1;
}
void change(int x,int y){
if(vis[x]){
update(x);
a[x]=y;
update(x);
}
else a[x]=y;
}
void solve(){
int l=1,r=0,now=0;
for(int i=1;i<=cnt;i++){
for(int j=now+1;j<=qu[i].pre;j++)
change(ch[j].pos,ch[j].y);
for(int j=now;j>qu[i].pre;j--)
change(ch[j].pos,ch[j].x);
for(int j=r+1;j<=qu[i].r;j++) update(j);
for(int j=r;j>qu[i].r;j--) update(j);
for(int j=l-1;j>=qu[i].l;j--) update(j);
for(int j=l;j<qu[i].l;j++) update(j);
ans[qu[i].id]=res;
l=qu[i].l,r=qu[i].r,now=qu[i].pre;
}
}
int main(){
freopen("data.in","r",stdin);//
scanf("%d%d",&n,&m);
int t=sqrt(n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
pos[i]=(i-1)/t+1;
}
for(int i=1;i<=m;i++){
char op[5];
int x,y;
scanf("%s%d%d",op,&x,&y);
if(op[0]=='R'){
ch[++tot]=(op1){x,b[x],y};
b[x]=y;
}
else qu[++cnt]=(op2){tot,x,y,cnt};
}
sort(qu+1,qu+cnt+1,cmp);
solve();
for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: