bzoj2120: 数颜色(BIT套主席树+set/分块)

Posted Sakits

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2120: 数颜色(BIT套主席树+set/分块)相关的知识,希望对你有一定的参考价值。

  带修改的 HH的项链。

  带修改考虑用BIT套主席树,查区间里有几个不同的数用a[i]上次出现的位置pre[i]<l的数有几个来算就好了。

  考虑怎么修改。修改i的时候,我们需要改变i同颜色的后继的pre,加入新的颜色,并且找到i在新颜色中的前驱后继,更改自己的pre和在新颜色中后继的pre,于是用一个set来维护每种颜色的前驱后继就好了。

技术分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
#include<set> 
using namespace std;
const int maxn=500010,inf=1e9;
struct poi{int sum,lt,rt;}tree[maxn<<2]; 
int n,m,sz,N,x,delta;
int a[maxn],b[maxn],q1[maxn],q2[maxn],root[maxn],pos[maxn];
char ch[maxn][1];
set<int>s[maxn];
set<int>::iterator pre,it,last;
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
inline int lowbit(int x){return x&-x;}
void update(int &x,int l,int r,int cx,int delta)
{
    tree[++sz]=tree[x];tree[sz].sum+=delta;x=sz;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(cx<=mid)update(tree[x].lt,l,mid,cx,delta);
    else update(tree[x].rt,mid+1,r,cx,delta); 
}
int query(int x,int l,int r,int cl,int cr)
{
    if(cl<=l&&r<=cr)return tree[x].sum;
    int mid=(l+r)>>1,ret=0;
    if(cl<=mid)ret+=query(tree[x].lt,l,mid,cl,cr);
    if(cr>mid)ret+=query(tree[x].rt,mid+1,r,cl,cr);
    return ret;
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)read(a[i]),b[++N]=a[i];
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ch[i]);read(q1[i]);read(q2[i]);
        if(ch[i][0]==R)b[++N]=q2[i];
    }
    sort(b+1,b+1+N);N=unique(b+1,b+1+N)-b-1;
    for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+N,a[i])-b;
    for(int i=1;i<=n;i++)
    { 
        for(int j=i;j<=n;j+=lowbit(j))
        update(root[j],0,N,pos[a[i]],1);
        s[a[i]].insert(i);pos[a[i]]=i;
    }
    for(int i=1;i<=N;i++)s[i].insert(0);
    for(int i=1;i<=m;i++)
    {
        if(ch[i][0]==Q)
        {
            int ans=0;
            for(int j=q1[i]-1;j;j-=lowbit(j))ans-=query(root[j],0,N,0,q1[i]-1);
            for(int j=q2[i];j;j-=lowbit(j))ans+=query(root[j],0,N,0,q1[i]-1);
            printf("%d\n",ans);
        }
        else
        {
            pre=it=last=s[a[q1[i]]].find(q1[i]);pre--;last++;
            if(last!=s[a[q1[i]]].end())
            {
                for(int j=*last;j<=n;j+=lowbit(j))update(root[j],0,N,q1[i],-1);
                for(int j=*last;j<=n;j+=lowbit(j))update(root[j],0,N,*pre,1);
            }
            q2[i]=lower_bound(b+1,b+1+N,q2[i])-b;
            for(int j=q1[i];j<=n;j+=lowbit(j))update(root[j],0,N,*pre,-1);
            s[a[q1[i]]].erase(it);a[q1[i]]=q2[i];s[a[q1[i]]].insert(q1[i]);
            pre=last=s[a[q1[i]]].find(q1[i]);pre--;last++; 
            for(int j=q1[i];j<=n;j+=lowbit(j))update(root[j],0,N,*pre,1);
            if(last!=s[a[q1[i]]].end())
            {
                for(int j=*last;j<=n;j+=lowbit(j))update(root[j],0,N,*pre,-1);
                for(int j=*last;j<=n;j+=lowbit(j))update(root[j],0,N,q1[i],1);
            } 
        }
    }
}
View Code

  分块的做法等会补...

 

以上是关于bzoj2120: 数颜色(BIT套主席树+set/分块)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2120

BZOJ 3110: [Zjoi2013]K大数查询( 树状数组套主席树 )

BZOJ2120数颜色(树套树+set)

bzoj1878: [SDOI2009]HH的项链(主席树/离线+BIT)

bzoj4771 -- dfs序+倍增+主席树

[国家集训队][bzoj2120] 数颜色 [带修改莫队]