BZOJ2120&2453数颜色——线段树套平衡树(treap)+set

题目描述

墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令: 1、 Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔。 2、 R P Col 把第P支画笔替换为颜色Col。为了满足墨墨的要求,你知道你需要干什么了吗?

输入

第1行两个整数N,M,分别代表初始画笔的数量以及墨墨会做的事情的个数。第2行N个整数,分别代表初始画笔排中第i支画笔的颜色。第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

样例输入

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

样例输出

4
4
3
4

提示

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

 
  对于每个点,记录这个点的颜色上一次出现的位置作为这个点的点权,每次查询l,r就相当于查询l到r之间点权小于l的点有多少个。实现起来直接用树套树就好了,外层用线段树维护序列区间信息,内层平衡树维护区间排名,每次只要找线段树对应点的平衡树内l的排名就好了。但修改比较麻烦,每次修改x点需要改变x修改前颜色中x的后继的前驱、x的前驱和修改后颜色中x的后继的前驱。对于每种颜色开一个set来维护前驱后继,每次修改时对应修改就好了,但要注意判断x是否有前驱和后继。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int x,y;
int n,m;
int tot;
int opt;
char ch[3];
int a[50010];
int v[2000010];
int w[2000010];
int t[2000010];
int l[500010];
int r[500010];
int ls[2000010];
int rs[2000010];
int pre[50010];
int suf[50010];
int size[2000010];
int root[500010];
map<int,int>b;
set<int>s[1000010];
set<int>::iterator it;
int inbuild(int k)
{
    tot++;
    t[tot]=rand();
    v[tot]=k;
    w[tot]=1;
    size[tot]=1;
    ls[tot]=rs[tot]=0;
    return tot;
}
void updata(int rt)
{
    size[rt]=size[ls[rt]]+size[rs[rt]]+w[rt];
}
void lturn(int &rt)
{
    int t=rs[rt];
    rs[rt]=ls[t];
    ls[t]=rt;
    updata(rt);
    updata(t);
    rt=t;
}
void rturn(int &rt)
{
    int t=ls[rt];
    ls[rt]=rs[t];
    rs[t]=rt;
    updata(rt);
    updata(t);
    rt=t;
}
void insert(int &rt,int k)
{
    if(!rt)
    {
        rt=inbuild(k);
        return ;
    }
    if(v[rt]==k)
    {
        w[rt]++;
    }
    else
    {   
        if(k<v[rt])
        {
            insert(ls[rt],k);
            if(t[ls[rt]]<t[rt])
            {
                rturn(rt);
            }
        }
        else
        {
            insert(rs[rt],k);
            if(t[rs[rt]]<t[rt])
            {
                lturn(rt);
            }
        }
    }
    updata(rt);
}
void del(int &rt,int k)
{
    if(v[rt]<k)
    {
        del(rs[rt],k);
    }
    else if(v[rt]>k)
    {
        del(ls[rt],k);
    }
    else
    {
        if(w[rt]>1)
        {
            w[rt]--;
        }
        else
        {
            if(!ls[rt]||!rs[rt])
            {
                rt=ls[rt]+rs[rt];
            }
            else
            {
                if(t[ls[rt]]<t[rs[rt]])
                {
                    rturn(rt);
                    del(rs[rt],k);
                }
                else
                {
                    lturn(rt);
                    del(ls[rt],k);
                }
            }
        }
    }
    if(rt)
    {
        updata(rt);
    }
}
int inrank(int rt,int k)
{
    if(!rt)
    {
        return 0;
    }
    if(v[rt]==k)
    {
        return size[ls[rt]];
    }
    else if(v[rt]<k)
    {
        return size[ls[rt]]+w[rt]+inrank(rs[rt],k);
    }
    else
    {
        return inrank(ls[rt],k);
    }
}
void outbuild(int rt,int L,int R)
{
    l[rt]=L;
    r[rt]=R;
    for(int i=L;i<=R;i++)
    {
        insert(root[rt],pre[i]);
    }
    if(L!=R)
    {
        int mid=(L+R)>>1;
        outbuild(rt<<1,L,mid);
        outbuild(rt<<1|1,mid+1,R);
    }
}
void change(int rt,int x,int y)
{
    del(root[rt],pre[x]);
    insert(root[rt],y);
    if(l[rt]!=r[rt])
    {
        int mid=(l[rt]+r[rt])>>1;
        if(x<=mid)
        {
            change(rt<<1,x,y);
        }
        else
        {
            change(rt<<1|1,x,y);
        }
    }
}
int outrank(int rt,int L,int R,int k)
{
    if(L<=l[rt]&&r[rt]<=R)
    {
        return inrank(root[rt],k);
    }
    int mid=(l[rt]+r[rt])>>1;
    if(R<=mid)
    {
        return outrank(rt<<1,L,R,k);
    }
    else if(L>mid)
    {
        return outrank(rt<<1|1,L,R,k);
    }
    return outrank(rt<<1,L,R,k)+outrank(rt<<1|1,L,R,k);
}
int main()
{
    srand(12378);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pre[i]=b[a[i]];
        suf[b[a[i]]]=i;
        b[a[i]]=i;
        s[a[i]].insert(i);
    }
    for(int i=1;i<=n;i++)
    {
        if(!suf[i])
        {
            suf[i]=n+1;
        }
    }
    outbuild(1,1,n);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ch);
        if(ch[0]=='R')
        {
            scanf("%d%d",&x,&y);
            if(a[x]==y)
            {
                continue;
            }
            if(pre[x])
            {
                suf[pre[x]]=suf[x];
            }
            if(suf[x]!=n+1)
            {
                change(1,suf[x],pre[x]);
                pre[suf[x]]=pre[x];
            }
            s[a[x]].erase(x);
            a[x]=y;
            s[a[x]].insert(x);
            it=s[a[x]].lower_bound(x);
            if(it!=s[a[x]].begin())
            {
                it--;
                suf[(*it)]=x;
                change(1,x,(*it));
                pre[x]=(*it);
                it++;
            }
            else
            {
                change(1,x,0);
                pre[x]=0;
            }
            if(++it!=s[a[x]].end())
            {
                suf[x]=(*it);
                change(1,(*it),x);
                pre[(*it)]=x;
            }
            else
            {
                suf[x]=n+1;
            }
        }
        else
        {
            scanf("%d%d",&x,&y);
            printf("%d\n",outrank(1,x,y,x));
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/Khada-Jhin/p/9546502.html
今日推荐