[bzoj2120] 数颜色
Description
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?
Input
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
Output
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
Sample Input
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
Sample Output
4
4
3
4
HINT
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
solution
设\(pre_i\)表示在当前点左边和当前点颜色相同并且和当前点距离最近的点。
那么对于Q x y
,答案为:
\[\sum_{i=x}^{y}[pre_i<x]
\]
那么可以转化为求一个区间内小于\(x\)的数有多少个,那么拿个树状数组套权值线段树或树状数组套平衡树或线段树套平衡树什么的维护下都行。(后面两个没写过,不知道常数足不足以通过)
对于\(pre_i\),可以开\(1e5\)个\(set\)维护下就行了。
不要瞎用static!!!(我被坑了好久)
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 1e5+1;
int col,n,m,pre[maxn],arr[maxn];
map<int,int > mp;
set<int > s[maxn];
#define mid ((l+r)>>1)
int ls[maxn*100],rs[maxn*100],sum[maxn*100],tot;
struct Segment_Tree {
int rt;
void modify(int &p,int l,int r,int x,int v) {
if(!p) p=++tot;
if(l==r) {sum[p]+=v;return ;}
if(x<=mid) modify(ls[p],l,mid,x,v);
else modify(rs[p],mid+1,r,x,v);
sum[p]=sum[ls[p]]+sum[rs[p]];
}
int query(int p,int l,int r,int x) {
if(!p||l==r) return 0;
if(x<=mid) return query(ls[p],l,mid,x);
else return query(rs[p],mid+1,r,x)+sum[ls[p]];
}
};
struct Binary_Indexed_Tree {
Segment_Tree sgt[maxn];
void modify(int p,int x,int v) {
for(;p<=n;p+=p&-p) sgt[p].modify(sgt[p].rt,0,n+m,x,v);
}
int query(int r,int x) {
int ans=0;
for(;r;r-=r&-r) ans+=sgt[r].query(sgt[r].rt,0,n+m,x);
return ans;
}
}BIT;
int main() {
read(n),read(m);
//for(int i=1;i<maxn;i++) s[i].insert(0),s[i].insert(maxn);
for(int i=1,c;i<=n;i++) {
read(c),c=(mp[c]?mp[c]:(mp[c]=++col));
if(!s[c].empty()) {
set<int>::iterator t=s[c].end();--t;
pre[i]=*t;
}
s[c].insert(i),arr[i]=c;
BIT.modify(i,pre[i],1);
}
for(int i=1;i<=m;i++) {
char ss[5];int x,y;scanf("%s",ss+1);read(x),read(y);
if(ss[1]=='Q') write(BIT.query(y,x)-x+1);
else {
y=mp[y]?mp[y]:(mp[y]=++col);
set<int> :: iterator t=s[arr[x]].find(x);++t;
if(t!=s[arr[x]].end()) {
BIT.modify(*t,pre[*t],-1);
pre[*t]=pre[x];
BIT.modify(*t,pre[*t],1);
}
s[arr[x]].erase(x),arr[x]=y,s[arr[x]].insert(x);
t=s[y].find(x);
BIT.modify(x,pre[x],-1);
if(t!=s[arr[x]].begin()) t--,pre[x]=*t,t++;else pre[x]=0;
BIT.modify(x,pre[x],1);t++;
if(t!=s[arr[x]].end()) {
int now=*t;
BIT.modify(now,pre[now],-1);
pre[now]=x;
BIT.modify(now,pre[now],1);
}
//for(int i=1;i<=n;i++) printf("%d ",pre[i]);puts("");
}
}
return 0;
}