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。

 
带修改莫队模板题
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct lty
{
	int l,r,num,tim;
}q[10010];
struct miku
{
	int x,y;
}a[10010];
int res;
int v[1000010];
int s[100010];
int ans[100010];
int num,cnt;
int n,m;
int block;
char ch[20];
bool cmp(lty a,lty b)
{
	return (a.l/block==b.l/block)?(a.r==b.r?a.tim<b.tim:a.r<b.r):a.l<b.l;
}
void del(int x)
{
	if(v[x]==1)
	{
		res--;
	}
	v[x]--;
}
void ins(int x)
{
	if(!v[x])
	{
		res++;
	}
	v[x]++;
}
void change(int l,int r,int id)
{
	if(a[id].x>=l&&a[id].x<=r)
	{
		if(--v[s[a[id].x]]==0)
		{
			res--;
		}
		if(++v[a[id].y]==1)
		{
			res++;
		}
	}
	swap(a[id].y,s[a[id].x]);
}
int main()
{
	scanf("%d%d",&n,&m);
	block=pow(n,2/3);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&s[i]);
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%s",ch);
		if(ch[0]=='Q')
		{
			cnt++;
			scanf("%d%d",&q[cnt].l,&q[cnt].r);
			q[cnt].num=cnt,q[cnt].tim=num;
		}
		else
		{
			num++;
			scanf("%d%d",&a[num].x,&a[num].y);
		}
	}
	sort(q+1,q+1+cnt,cmp);
	int L=1,R=0,now=0;
	for(int i=1;i<=cnt;i++)
	{
		while(L>q[i].l)
		{
			L--;
			ins(s[L]);
		}
		while(R<q[i].r)
		{
			R++;
			ins(s[R]);
		}
		while(L<q[i].l)
		{
			del(s[L]);
			L++;
		}
		while(R>q[i].r)
		{
			del(s[R]);
			R--;
		}
		while(now<q[i].tim)
		{
			now++;
			change(q[i].l,q[i].r,now);
		}
		while(now>q[i].tim)
		{
			change(q[i].l,q[i].r,now);
			now--;
		}
		ans[q[i].num]=res;
	}
	for(int i=1;i<=cnt;i++)
	{
		printf("%d\n",ans[i]);
	}
}
对于每个点,记录这个点的颜色上一次出现的位置作为这个点的点权,每次查询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));
        }
    }
}
posted @ 2018-08-28 10:25  The_Virtuoso  阅读(248)  评论(0编辑  收藏  举报