题目描述
墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?
输入
第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。
输出
对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。
样例输入
6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6
样例输出
4
4
3
4
4
3
4
提示
对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。
对于每个点,记录这个点的颜色上一次出现的位置作为这个点的点权,每次查询l,r就相当于查询l到r之间点权小于l的点有多少个。实现起来直接用树套树就好了,外层用线段树维护序列区间信息,内层平衡树维护区间排名,每次只要找线段树对应点的平衡树内l的排名就好了。但修改比较麻烦,每次修改x点需要改变x修改前颜色中x的后继的前驱、x的前驱和修改后颜色中x的后继的前驱。对于每种颜色开一个set来维护前驱后继,每次修改时对应修改就好了,但要注意判断x是否有前驱和后继。
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define ll long long using namespace std; int x,y; int n,m; int tot; int opt; char ch[3]; int a[50010]; int v[2000010]; int w[2000010]; int t[2000010]; int l[500010]; int r[500010]; int ls[2000010]; int rs[2000010]; int pre[50010]; int suf[50010]; int size[2000010]; int root[500010]; map<int,int>b; set<int>s[1000010]; set<int>::iterator it; int inbuild(int k) { tot++; t[tot]=rand(); v[tot]=k; w[tot]=1; size[tot]=1; ls[tot]=rs[tot]=0; return tot; } void updata(int rt) { size[rt]=size[ls[rt]]+size[rs[rt]]+w[rt]; } void lturn(int &rt) { int t=rs[rt]; rs[rt]=ls[t]; ls[t]=rt; updata(rt); updata(t); rt=t; } void rturn(int &rt) { int t=ls[rt]; ls[rt]=rs[t]; rs[t]=rt; updata(rt); updata(t); rt=t; } void insert(int &rt,int k) { if(!rt) { rt=inbuild(k); return ; } if(v[rt]==k) { w[rt]++; } else { if(k<v[rt]) { insert(ls[rt],k); if(t[ls[rt]]<t[rt]) { rturn(rt); } } else { insert(rs[rt],k); if(t[rs[rt]]<t[rt]) { lturn(rt); } } } updata(rt); } void del(int &rt,int k) { if(v[rt]<k) { del(rs[rt],k); } else if(v[rt]>k) { del(ls[rt],k); } else { if(w[rt]>1) { w[rt]--; } else { if(!ls[rt]||!rs[rt]) { rt=ls[rt]+rs[rt]; } else { if(t[ls[rt]]<t[rs[rt]]) { rturn(rt); del(rs[rt],k); } else { lturn(rt); del(ls[rt],k); } } } } if(rt) { updata(rt); } } int inrank(int rt,int k) { if(!rt) { return 0; } if(v[rt]==k) { return size[ls[rt]]; } else if(v[rt]<k) { return size[ls[rt]]+w[rt]+inrank(rs[rt],k); } else { return inrank(ls[rt],k); } } void outbuild(int rt,int L,int R) { l[rt]=L; r[rt]=R; for(int i=L;i<=R;i++) { insert(root[rt],pre[i]); } if(L!=R) { int mid=(L+R)>>1; outbuild(rt<<1,L,mid); outbuild(rt<<1|1,mid+1,R); } } void change(int rt,int x,int y) { del(root[rt],pre[x]); insert(root[rt],y); if(l[rt]!=r[rt]) { int mid=(l[rt]+r[rt])>>1; if(x<=mid) { change(rt<<1,x,y); } else { change(rt<<1|1,x,y); } } } int outrank(int rt,int L,int R,int k) { if(L<=l[rt]&&r[rt]<=R) { return inrank(root[rt],k); } int mid=(l[rt]+r[rt])>>1; if(R<=mid) { return outrank(rt<<1,L,R,k); } else if(L>mid) { return outrank(rt<<1|1,L,R,k); } return outrank(rt<<1,L,R,k)+outrank(rt<<1|1,L,R,k); } int main() { srand(12378); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); pre[i]=b[a[i]]; suf[b[a[i]]]=i; b[a[i]]=i; s[a[i]].insert(i); } for(int i=1;i<=n;i++) { if(!suf[i]) { suf[i]=n+1; } } outbuild(1,1,n); for(int i=1;i<=m;i++) { scanf("%s",ch); if(ch[0]=='R') { scanf("%d%d",&x,&y); if(a[x]==y) { continue; } if(pre[x]) { suf[pre[x]]=suf[x]; } if(suf[x]!=n+1) { change(1,suf[x],pre[x]); pre[suf[x]]=pre[x]; } s[a[x]].erase(x); a[x]=y; s[a[x]].insert(x); it=s[a[x]].lower_bound(x); if(it!=s[a[x]].begin()) { it--; suf[(*it)]=x; change(1,x,(*it)); pre[x]=(*it); it++; } else { change(1,x,0); pre[x]=0; } if(++it!=s[a[x]].end()) { suf[x]=(*it); change(1,(*it),x); pre[(*it)]=x; } else { suf[x]=n+1; } } else { scanf("%d%d",&x,&y); printf("%d\n",outrank(1,x,y,x)); } } }