zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",outrank(1,x,y,x));
            }
        }
    }
  • 相关阅读:
    CTF简介
    最先与最后
    记一次某校版facemash的搭建
    ipv6入门
    win10开启IPv6的两种方法
    安装 Go 1.11 在 Ubuntu 18.04 & 16.04 LTS
    python开发者的AsyncIO
    Python 异步--Await the Future
    Python元类
    alias 和 unalias 命令
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9546502.html
Copyright © 2011-2022 走看看