初始给定一个长度为n的数列,给定m次操作,每次要么询问区间[L,R]中有多少种不同的数字,要么修改一个位置的数值。
n<=1e4,m<=1e4,ai<=1e6
询问区间内有多少种不同的数字容易联想到主席树,这边带修改的话那么就树套树了
先回顾一下如果不带修改怎么做,一种做法是对每个位置维护上一个跟当前有相同数字的位置pre[i],然后在区间[L,R]中查询pre值小于L的个数,即相当于把每个数字的贡献放到第一次出现在这个区间里的位置上。
带修改的话我们需要考虑改变一个位置的数值会影响哪些位置的pre,那么我们会影响与原先数值相同的下一个位置的pre、当前位置的pre,以及与新数值相同的下一个位置的pre。
为了快速定位这些位置,其实我们可以对每个数值维护一个set,然后在里面二分找前驱后继,STL大法好,
然后就是相当于单点修改一些位置的pre,然后就是树套树的事了,我这边写的是树状数组套动态开点权值线段树。
二分的时候一些临界的条件需要特判一下,可能这边写得有点丑。
时间复杂度O(Nlog^2N)
#includeusing namespace std; const int maxm=1e6; const int maxn=1e4; set<int> s[maxm+5]; int n,m,l,r; int root[maxn+5]; int pre[maxn+5],a[maxn+5]; int lowbit(int x) { return x&(-x); } struct SegmentTree { int lc,rc; int cnt; }b[maxn<<7]; int tot=0; int build() { int p=++tot; b[p].lc=b[p].rc=b[p].cnt=0; return p; } void pushup(int p) { b[p].cnt=b[b[p].lc].cnt+b[b[p].rc].cnt; } void update(int &p,int l,int r,int pos,int val) { if (!p) p=build(); if (l==r) { b[p].cnt+=val; return ; } int mid=(l+r)>>1; if (pos<=mid) update(b[p].lc,l,mid,pos,val); else update(b[p].rc,mid+1,r,pos,val); pushup(p); } int getLessCnt(int p,int l,int r,int val) { if (!p) return 0; if (l==r) { if (l return b[p].cnt; return 0; } int mid=(l+r)>>1; if (val<=mid) return getLessCnt(b[p].lc,l,mid,val); else return b[b[p].lc].cnt+getLessCnt(b[p].rc,mid+1,r,val); } char str[10]; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); if (s[a[i]].size()) pre[i]=(*s[a[i]].rbegin()); s[a[i]].insert(i); } for (int i=1;i<=n;i++) for (int j=i;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[i],1); while (m--) { scanf("%s",str); if (str[0]=='Q') { scanf("%d%d",&l,&r); int t=0; for (int j=r;j;j-=lowbit(j)) t+=getLessCnt(root[j],0,n,l); for (int j=l-1;j;j-=lowbit(j)) t-=getLessCnt(root[j],0,n,l); printf("%d\n",t); } else { scanf("%d%d",&l,&r); s[a[l]].erase(l); set<int>::iterator it1=lower_bound(s[a[l]].begin(),s[a[l]].end(),l); if (it1!=s[a[l]].end()) { int p1=(*it1); if (it1==s[a[l]].begin()) { pre[p1]=0; for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,l,-1); for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,0,1); } else { it1--; pre[p1]=(*it1); for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,l,-1); for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,(*it1),1); } } set<int>::iterator it2=lower_bound(s[r].begin(),s[r].end(),l); if (it2!=s[r].begin()) { it2--; for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[l],-1); for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,(*it2),1); pre[l]=(*it2); it2++; } else { for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[l],-1); for (int j=l;j<=n;j+=lowbit(j)) update(root[j],0,n,0,1); pre[l]=0; } if (it2!=s[r].end()) { int p1=(*it2); for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,pre[p1],-1); for (int j=p1;j<=n;j+=lowbit(j)) update(root[j],0,n,l,1); pre[p1]=l; } s[r].insert(l); a[l]=r; } } return 0; }