zoukankan      html  css  js  c++  java
  • SPOJ DQUERY (主席树求区间不同数个数)

    题意:找n个数中无修改的区间不同数个数

    题解:使用主席树在线做,我们不能使用权值线段树建主席树

    我们需要这么想:从左向右添加一到主席树上,添加的是该数字处在的位置

    但是如果该数字前面出现过,就在此版本的主席树上的前面出现的位置减一,接着才在此位置上添一

    这样查找是按照右区间版本的主席树来找(lef,rig)的数字

    因为要将此区间每个不同的数都处在最后出现的位置

    /*在线求区间内不同的数的个数:从头到尾添加到线段树(不是权值线段树,是存值的线段树)中
    如果此数之前出现过就先减去,接着再加,最后在区间(l,r)中找到root[r]这个历史版本*/
    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define dir(a,b) (a>>b)
    const int Max=30010;
    int root[Max],tot,val[Max];
    struct node
    {
        int lef,rig,sum;
    }msegtr[Max*40];
    map<int,int> mp;
    void Init()
    {
        tot=0;
        msegtr[0].lef=msegtr[0].rig=msegtr[0].sum=0;
        root[0]=0;
        mp.clear();
        return;
    }
    void Create(int sta,int enn,int &x,int y,int pos,int aad)
    {
        msegtr[++tot]=msegtr[y];
        msegtr[tot].sum+=aad;
        x=tot;
        if(sta==enn)
            return;
        int mid=dir(sta+enn,1);
        if(mid>=pos)
            Create(sta,mid,msegtr[x].lef,msegtr[y].lef,pos,aad);
        else
        Create(mid+1,enn,msegtr[x].rig,msegtr[y].rig,pos,aad);
        return;
    }
    int Query(int sta,int enn,int x,int y)//只有左边有界限
    {
        if(sta>=y)
            return msegtr[x].sum;
        int mid=dir(sta+enn,1);
        if(mid>=y)
            return Query(sta,mid,msegtr[x].lef,y)+msegtr[msegtr[x].rig].sum;
        else
            return Query(mid+1,enn,msegtr[x].rig,y);
    }
    int main()
    {
        int n,m,temp;
        int lef,rig;
        while(~scanf("%d",&n))
        {
             Init();
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&val[i]);
            if(!mp.count(val[i]))//直接加
            {
                Create(1,n,root[i],root[i-1],i,1);//注意是在i这个位置加1,不是权值线段树的val[i]位置加1
            }
            else
            {
                Create(1,n,temp,root[i-1],mp[val[i]],-1);//先在原位置减去1
                Create(1,n,root[i],temp,i,1);
            }
            mp[val[i]]=i;
        }
        scanf("%d",&m);
        for(int i=0;i<m;++i)
        {
            scanf("%d %d",&lef,&rig);
            printf("%d
    ",Query(1,n,root[rig],lef));//在rig的历史版本上找(lef,rig)的值
        }
        }
        return 0;
    }
  • 相关阅读:
    3(翻译)如何在cocos2d里面使用动画和spritesheet
    Objectivec2.0 每种数据类型定义属性的方法
    cocos2d 入门必备4个基本概念
    如何在Mac上搭建自己的服务器——Nginx
    JN_0001:在微信朋友圈分享时长大于10s的视频
    JN_0002:Win10禁止U盘拷贝文件的方法
    abstract class 和 interface区别
    ref和out
    .Net配置错误页
    Unity3d 物体沿着正七边形轨迹移动
  • 原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/5936713.html
Copyright © 2011-2022 走看看