【bzoj2120】数颜色

来源:互联网 发布:网络四十大禁书 编辑:程序博客网 时间:2024/06/05 14:28

2120: 数颜色

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支画笔中共有几种不同颜色的画笔。


题意:有一个区间,支持两种操作:修改一个值,查询一个区间内有多少个不同的数。

可以对于每一个位置,维护pre,即这个值前面最后一次出现的位置,和sub,即这个值后面第一次出现的位置。查询[l,r]区间有多少个不同的数,就是查询[l,r]区间有多少个位置的pre<l。很显然,这个东西可以用主席树解决,询问时差分一下即可。带修改操作也真是恶心,改成树状数组套权值线段树。

再来说一下怎么维护pre和sub。要把权值离散化一下,再开n棵平衡树对应每种权值。修改时再各种乱搞,把各种贡献加加减减的,并找到新的值的pre和sub。细节详见代码。我打了一棵替罪羊树,发现还真是挺快的,第一次进RANK前3页。

坑啊!我的数组开成10000,不知怎么的就WA了一个上午!改成11000就AC了。不是应该RE的吗 = =

代码:

#include<cstdio>#include<algorithm>using namespace std;inline int rd(){char ch=getchar();int ret=0,f=1;while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}return ret*f;}const int N=11005;int n,m,cnt,a[N],hash[2*N],pre[N],sub[N],last[N],root[N];int sumv[N*100],lc[N*100],rc[N*100],L[10005],R[10005];int mempool[2*N],siz[2*N],tot[2*N],key[2*N],del[2*N],pos[2*N],ch[2*N][2];struct query{char s[5];int l,r;}q[N];int getid(int x){return lower_bound(hash+1,hash+hash[0]+1,x)-hash;}int lowbit(int x){return x&(-x);}struct ScapeGoatTree{int root;int *goat;int rnk(int x){int k=root,ret=1;while(k){if(x<=key[k]) k=ch[k][0];else{ret+=siz[ch[k][0]]+del[k];k=ch[k][1];}}return ret;}int kth(int x){if(x<1||x>siz[root]) return 0;int k=root;while(k){if(del[k]&&x==siz[ch[k][0]]+1) return key[k];else if(x<=siz[ch[k][0]]+del[k]) k=ch[k][0];else{x-=siz[ch[k][0]]+del[k];k=ch[k][1];}}}void dfs(int k){if(!k) return;dfs(ch[k][0]);if(del[k]) pos[++pos[0]]=k;else mempool[++mempool[0]]=k;dfs(ch[k][1]);}void build(int &k,int l,int r){if(l>r){k=0;return;}int mid=(l+r)/2;k=pos[mid];build(ch[k][0],l,mid-1);build(ch[k][1],mid+1,r);siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+1;tot[k]=tot[ch[k][0]]+tot[ch[k][1]]+1;}void rebuild(int &k){pos[0]=0;dfs(k);build(k,1,pos[0]);}void insert(int &k,int x){if(!k){k=mempool[mempool[0]--];key[k]=x;siz[k]=tot[k]=del[k]=1;ch[k][0]=ch[k][1]=0;return;}siz[k]++;tot[k]++;if(x<=key[k]) insert(ch[k][0],x);else insert(ch[k][1],x);if(siz[k]*0.75<max(siz[ch[k][0]],siz[ch[k][1]]))goat=&k;}void insert(int x){goat=NULL;insert(root,x);if(goat) rebuild(*goat);}void remove(int k,int x){if(del[k]&&x==siz[ch[k][0]]+1){siz[k]--;del[k]=0;return;}siz[k]--;if(x<=siz[ch[k][0]]+del[k])remove(ch[k][0],x);else remove(ch[k][1],x-siz[ch[k][0]]-del[k]);}void remove(int x){remove(root,rnk(x));if(siz[root]<tot[root]*0.75) rebuild(root);}}sgt[N];void update(int &o,int l,int r,int k,int v){if(!o) o=++cnt;sumv[o]+=v;if(l==r) return;int mid=(l+r)/2;if(k<=mid) update(lc[o],l,mid,k,v);else update(rc[o],mid+1,r,k,v);}int query(int l,int r,int k){if(l==r) return 0;int mid=(l+r)/2;if(k<=mid){for(int i=1;i<=L[0];i++) L[i]=lc[L[i]];for(int i=1;i<=R[0];i++) R[i]=lc[R[i]];return query(l,mid,k);}else{int sum=0;for(int i=1;i<=L[0];i++){sum-=sumv[lc[L[i]]];L[i]=rc[L[i]];}for(int i=1;i<=R[0];i++){sum+=sumv[lc[R[i]]];R[i]=rc[R[i]];}return sum+query(mid+1,r,k);}}int solvequery(int l,int r){L[0]=R[0]=0;for(int i=l-1;i;i-=lowbit(i)) L[++L[0]]=root[i];for(int i=r;i;i-=lowbit(i)) R[++R[0]]=root[i];return query(0,n,l);}int main(){for(int i=1;i<=20000;i++) mempool[i]=i;mempool[0]=20000;n=rd(),m=rd();for(int i=1;i<=n;i++)hash[++hash[0]]=a[i]=rd();for(int i=1;i<=m;i++){scanf("%s",q[i].s);q[i].l=rd(),q[i].r=rd();if(q[i].s[0]=='R') hash[++hash[0]]=q[i].r;}sort(hash+1,hash+hash[0]+1);hash[0]=unique(hash+1,hash+hash[0]+1)-hash-1;for(int i=1;i<=n;i++){a[i]=getid(a[i]);pre[i]=last[a[i]];if(last[a[i]]) sub[last[a[i]]]=i;last[a[i]]=i;sgt[a[i]].insert(i);for(int j=i;j<=n;j+=lowbit(j))update(root[j],0,n,pre[i],1);}for(int i=1;i<=m;i++){if(q[i].s[0]=='Q'){L[0]=R[0]=0;for(int j=q[i].l-1;j;j-=lowbit(j)) L[++L[0]]=root[j];for(int j=q[i].r;j;j-=lowbit(j)) R[++R[0]]=root[j];printf("%d\n",query(0,n,q[i].l));}else{q[i].r=getid(q[i].r);for(int j=q[i].l;j<=n;j+=lowbit(j))update(root[j],0,n,pre[q[i].l],-1);if(pre[q[i].l]) sub[pre[q[i].l]]=sub[q[i].l];if(sub[q[i].l]){for(int j=sub[q[i].l];j<=n;j+=lowbit(j))update(root[j],0,n,q[i].l,-1);for(int j=sub[q[i].l];j<=n;j+=lowbit(j))update(root[j],0,n,pre[q[i].l],1);pre[sub[q[i].l]]=pre[q[i].l];}sgt[a[q[i].l]].remove(q[i].l);sgt[q[i].r].insert(q[i].l);a[q[i].l]=q[i].r;pre[q[i].l]=sgt[q[i].r].kth(sgt[q[i].r].rnk(q[i].l)-1);sub[q[i].l]=sgt[q[i].r].kth(sgt[q[i].r].rnk(q[i].l)+1);for(int j=q[i].l;j<=n;j+=lowbit(j))update(root[j],0,n,pre[q[i].l],1);if(pre[q[i].l]) sub[pre[q[i].l]]=q[i].l;if(sub[q[i].l]){for(int j=sub[q[i].l];j<=n;j+=lowbit(j))update(root[j],0,n,pre[q[i].l],-1);for(int j=sub[q[i].l];j<=n;j+=lowbit(j))update(root[j],0,n,q[i].l,1);pre[sub[q[i].l]]=q[i].l;}}}return 0;}