• 洛谷/SPOJ SP3267 题解


    若想要深入学习主席树,传送门


    Description:

    给定数列 ({a_n}) ,求闭区间 ([l,r]) 的互异的个数。

    Method:

    扫描序列建立可持续化线段树,若此元素是第一次出现,就将对应的线段树中的位置加1;反之,就将上一个出现的元素对应的线段树中的位置减1,将此元素对应的线段树中的位置加1。

    对于查询的 ([l,r]) ,在第 (r) 个版本的线段树上查询位置 (l) ,对经过的区间中的和累加一下即可。

    Code:

    #include<bits/stdc++.h>
    #define int long long 
    #define Maxn 30010
    using namespace std;
    inline void read(int &x)
    {
        int f=1;x=0;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        x*=f;
    }
    int n,q;
    int a[Maxn]; 
    int tot=0;
    struct Segtree
    {
        int ls,rs,sum;
    }tree[Maxn<<5];
    int rt[Maxn];
    inline void Init(){tot=0;}
    inline void pushup(int rt)
    {
       tree[rt].sum=tree[tree[rt].ls].sum+tree[tree[rt].rs].sum;
    }
    inline int build(int l,int r)
    {
        int rt=++tot;
        if(l==r) 
        {
            tree[rt].sum=0;
            return rt;
        }
        int mid=(l+r)/2;
        tree[rt].ls=build(l,mid);
        tree[rt].rs=build(mid+1,r);
        pushup(rt);
        return rt;
    }
    int update(int k,int l,int r,int root,int val)
    {
        int rt=++tot;
        tree[rt]=tree[root];
        if(l==k&&r==k)
        {
            tree[rt].sum+=val;
            return rt;
        }
        int mid=(l+r)/2;
        if(k<=mid) tree[rt].ls=update(k,l,mid,tree[rt].ls,val);
        else tree[rt].rs=update(k,mid+1,r,tree[rt].rs,val);
        pushup(rt);
        return rt;
    }
    int query(int l,int r,int rt,int pos)
    {
        if(l==r) return tree[rt].sum;
        int mid=(l+r)/2;
        if(pos<=mid) return tree[tree[rt].rs].sum+query(l,mid,tree[rt].ls,pos);
        else return query(mid+1,r,tree[rt].rs,pos);
    }
    map<int,int>mp;
    signed main()
    {
        Init();
        read(n);
        for(int i=1;i<=n;i++)
        {
            read(a[i]);
        }
        rt[0]=build(1,n);
        for(int i=1;i<=n;i++)
        {
            if(mp.find(a[i])==mp.end())
            {
                mp[a[i]]=i;
                rt[i]=update(i,1,n,rt[i-1],1);	
            }else
            {
                int tmprt=update(mp[a[i]],1,n,rt[i-1],-1);
                rt[i]=update(i,1,n,tmprt,1);
            }
            mp[a[i]]=i;
        }
        read(q);
        while(q--)
        {
            int l,r;
            read(l),read(r);
            int ans=query(1,n,rt[r],l);
            printf("%lld
    ",ans);
        } 
        return 0;
    }
    
  • 相关阅读:
    反射类的字段
    反射类的方法(其中main方法比较特殊)
    反这类的构造函数(写框架时才会用到反射类)
    枚举
    进制转换小算法
    第一个小程序:用户登录
    Hello World!
    潭州课堂25班:Ph201805201 tornado 项目 第五课 增加用户系统-用户中心(课堂笔记)
    潭州课堂25班:Ph201805201 tornado 项目 第四课 增加用户注册登录(课堂笔记)
    潭州课堂25班:Ph201805201 tornado 项目 第三课 项目 图片上传,展示 (课堂笔记)
  • 原文地址:https://www.cnblogs.com/nth-element/p/11785032.html
Copyright © 2020-2023  润新知