您的位置:首页 > 其它

bzoj2120 数颜色 带修改的莫队

2017-12-29 22:38 288 查看

Description

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

HINT

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

Solution

带修改的莫队还是第一次做

很容易想到分块,但是对于修改操作我们不好弄。于是加一维(l,r,x)表示做到区间[l,r]并且已经做了x次修改,然后像普通莫队一样暴力离线改即可

一个小技巧就是在移动x的修改时候交换当前颜色和目标颜色,这样改回来的时候再次交换就行了(绕

Code

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define max(x,y) ((x)>(y)?(x):(y))
const int N=10005;
const int B=250;
struct data{int l,r,x,id,ans;}Q
,R
;
int t[N*B/2],c
;
int n,m,cnt_r=0,cnt_q=0,tot;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void del(int x) {if (!(--t[c[x]])) tot--;}
void add(int x) {if (++t[c[x]]==1) tot++;}
bool cmp1(data x,data y) {
int pxl=x.l/B;
int pxr=x.r/B;
int pyl=y.l/B;
int pyr=y.r/B;
return (pxl<pyl)||(pxl==pyl&&pxr<pyr)||(pxl==pyl&&pxr<pyr&&x.x<y.x);
}
bool cmp2(data x,data y) {return x.id<y.id;}
void modify(int x,int l,int r) {
if (l<=R[x].l&&R[x].l<=r) del(R[x].l);
std:: swap(c[R[x].l],R[x].r);
if (l<=R[x].l&&R[x].l<=r) add(R[x].l);
}
void solve() {
int x=0,l=1,r=1; add(1);
rep(i,1,cnt_q) {
for (;r<Q[i].r;r++) add(r+1);
for (;r>Q[i].r;r--) del(r);
for (;l<Q[i].l;l++) del(l);
for (;l>Q[i].l;l--) add(l-1);
for (;x<Q[i].x;x++) modify(x+1,l,r);
for (;x>Q[i].x;x--) modify(x,l,r);
Q[i].ans=tot;
}
}
int main(void) {
n=read(); m=read();
rep(i,1,n) c[i]=read();
rep(i,1,m) {
char opt[2];
scanf("%s",opt);
int l=read(),r=read();
if (opt[0]=='Q') Q[++cnt_q]=(data){l,r,cnt_r,cnt_q,0};
else R[++cnt_r]=(data){l,r,0,cnt_r,0};
}
std:: sort(Q+1,Q+cnt_q+1,cmp1);
solve();
std:: sort(Q+1,Q+cnt_q+1,cmp2);
rep(i,1,cnt_q) printf("%d\n",Q[i].ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: