数颜色:带修主席树/分块

解法一:主席树

题目可转化为带修[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;
}

 

posted @ 2019-06-30 16:51  _xuefeng  阅读(275)  评论(1编辑  收藏  举报