数颜色:带修主席树/分块
解法一:主席树
题目可转化为带修[L,R]内不同数的个数,就用主席树了。
权值主席树维护位置上的数的前驱,在求[L,R]内不同数的个数时就将R树与L-1树作差取<=L-1的数的个数。
修改时考虑对于pos这个位置改为col,会有另两个位置受影响。
一个是以pos为pre的位置,它的pre要变为pre[pos]。
一个是pos后第一个以col为颜色的位置,pre[pos]要变为这个位置的pre,这个位置的pre要变为pos(有点像前向星)。
注意!pos后可能不存在以col为颜色的位置,但前面有可能有col这个颜色!(即1 3 5 2 6,将pos=5的col变为3,后面没有3了,但是它的pre应为2)
所以当pos后不存在以col为颜色的位置时,再向前扫一边,看是否有col这个颜色,找最近的作为pre[pos].
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e5+10; 4 int n,m; 5 int col[N],head[N*10],pre[N],rt[N]; 6 #define lowbit(x) (x&(-x)) 7 struct Chairman_Tree{ 8 struct Tree{ 9 int lch,rch; 10 int size; 11 }node[N*500]; 12 int cnt; 13 void Update(int&x,int l,int r,int pos,int dat){ 14 int k=++cnt; 15 node[k]=node[x]; 16 x=k; 17 node[x].size+=dat; 18 if(l==r)return; 19 int mid=l+r>>1; 20 if(pos<=mid)Update(node[x].lch,l,mid,pos,dat); 21 else Update(node[x].rch,mid+1,r,pos,dat); 22 } 23 void Add(int x,int pos,int dat){ 24 while(x<=n){ 25 Update(rt[x],0,n,pos,dat); 26 x+=lowbit(x); 27 } 28 } 29 int query(int x,int l,int r,int pos){ 30 if(pos>=r)return node[x].size; 31 int mid=l+r>>1; 32 if(pos>mid)return node[node[x].lch].size+query(node[x].rch,mid+1,r,pos); 33 else return query(node[x].lch,l,mid,pos); 34 } 35 }CT; 36 int main(){ 37 //freopen("1.in","r",stdin); 38 scanf("%d%d",&n,&m); 39 for(int i=1;i<=n;++i){ 40 scanf("%d",&col[i]); 41 pre[i]=head[col[i]]; 42 head[col[i]]=i; 43 CT.Add(i,pre[i],1); 44 } 45 int L,R,pos,co,las_la,las_ne,ti_ne; 46 for(int oo=1;oo<=m;++oo){ 47 char ch[5];scanf("%s",ch); 48 if(ch[0]=='Q'){ 49 scanf("%d%d",&L,&R); 50 int ans=0; 51 if(L>R){puts("0");continue;} 52 if(L==R){puts("1");continue;} 53 if(L>n||R>n||L<1||R<1){puts("0");continue;} 54 for(int i=R;i;i-=lowbit(i))ans+=CT.query(rt[i],0,n,L-1); 55 for(int i=L-1;i;i-=lowbit(i))ans-=CT.query(rt[i],0,n,L-1); 56 printf("%d\n",ans); 57 } 58 else{ 59 las_la=0,las_ne=0,ti_ne=0; 60 scanf("%d%d",&pos,&co); 61 if(col[pos]==co){continue;} 62 CT.Add(pos,pre[pos],-1); 63 for(int i=pos+1;i<=n;++i){ 64 if(las_la&&las_ne)break; 65 if(col[i]==col[pos]&&!las_la)las_la=i; 66 if(col[i]==co&&!las_ne)las_ne=i; 67 } 68 if(las_la){ 69 CT.Add(las_la,pre[las_la],-1); 70 CT.Add(las_la,pre[pos],1); 71 pre[las_la]=pre[pos]; 72 } 73 if(las_ne){ 74 CT.Add(las_ne,pre[las_ne],-1); 75 CT.Add(las_ne,pos,1); 76 CT.Add(pos,pre[las_ne],1); 77 pre[pos]=pre[las_ne]; 78 pre[las_ne]=pos; 79 } 80 else{ 81 for(int i=1;i<=n-1;++i) 82 if(col[i]==co)ti_ne=i; 83 CT.Add(pos,ti_ne,1),pre[pos]=ti_ne; 84 } 85 col[pos]=co; 86 } 87 } 88 return 0; 89 }
解法二:分块
分块大法好
#include <iostream> #include <cstdio> #include <cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long LL ; const int N = 1e6+10; const int inf = 2147483647; const LL mod = 1e9+7; int lx[N],rx[N],id[N],a[N], p[N],last[N],pre[N];; int n, m; void reset(int x) { for(int i=lx[x];i<=rx[x];i++)p[i]=pre[i]; sort(p+lx[x],p+rx[x]+1); return ; } void update(int x,int v) { for(int i=0;i<=n;i++) last[a[i]]=0; a[x]=v; int i; for(int i=1;i<=n;i++) { int t=pre[i]; pre[i]=last[a[i]]; if(pre[i]!=t) reset(id[i]); last[a[i]]=i; } return ; } int get(int x,int v) { int num=0; int l=lx[x],r=rx[x],ans=-1; while(l<=r) { int mid=(l+r)/2; if(p[mid]<v)l=mid+1; else r=mid-1; } int an=lower_bound(p+lx[x],p+rx[x]+1,v)-p-1; return an-lx[x]+1; } int query(int l,int r) { int num=0; int al=id[l],ar=id[r]; if(al==ar) { for(int i=l;i<=r;i++) { if(pre[i]<l)num++; } return num; } for(int i=l;i<=rx[al];i++) if(pre[i]<l) num++; for(int i=lx[ar];i<=r;i++) if(pre[i]<l) num++; for(int i=al+1;i<ar;i++) num+=get(i,l); return num; } inline int read(){ int k=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();} return k*f; } int main() { n=read(); m=read(); int k=sqrt(n);if(k*k!=n)k++; for(int i=1;i<=k;i++) { lx[i]=(i-1)*k+1,rx[i]=min(i*k,n); for(int j=lx[i];j<=rx[i];j++) { a[j]=read(); pre[j]=last[a[j]]; last[a[j]]=j; p[j]=pre[j]; id[j]=i; } sort(p+lx[i],p+rx[i]+1); } char str[10]; while(m--) { int l, r; scanf("%s", str); l=read(); r=read(); if(str[0]=='Q') printf("%d\n",query(l,r)); else update(l,r); } return 0; }
Keep it simple and stupid.