• SPOJ D-query(主席树入门)


    • 题意: 求l,r区间中不同数字的个数
    • 思路: 主席树,第i颗树代表了插入a[i]后,1~i区间内的信息
    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N = 3e4+10;
    struct node{
        int l,r,sum;
    }sgt[N*40];
    int a[N],root[N],now;
    map<int,int> mp;    // 记录上一次 k 出现的位置
    void insert(int l,int r,int pre,int rt,int pos,int val){
        sgt[rt].sum = sgt[pre].sum; // 先将前一颗树的信息赋给当前树
        sgt[rt].l = sgt[pre].l; sgt[rt].r = sgt[pre].r; 
        if(l==r){   // 叶子节点直接更新     叶子节点sum 取值{0,1}
            sgt[rt].sum += val; return ;
        }
        int mid = (l+r)>>1;
        if(pos <= mid) insert(l,mid,sgt[pre].l,sgt[rt].l=++now,pos,val);    // 去左子树插入
        else insert(mid+1,r,sgt[pre].r,sgt[rt].r=++now,pos,val);            // 去右子树插入
        sgt[rt].sum = sgt[sgt[rt].l].sum + sgt[sgt[rt].r].sum;              // 更新父亲
    }
    int query(int rt,int l,int r,int L,int R){
        if(L >= l && R <= r)    return sgt[rt].sum;                         // 区间包含
        int mid = (L+R)>>1;
        int res = 0;
        if(l<=mid)  res += query(sgt[rt].l,l,r,L,mid);                      // 询问左子树
        if(r>mid)   res += query(sgt[rt].r,l,r,mid+1,R);                    // 询问右子树
        return res;
    }
    int main(){
        int l,r,k,n,q;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)   scanf("%d",&a[i]);
        for(int i=1;i<=n;++i){
            // 如果没有出现过 直接在i处增加1个
            if(!mp[a[i]]) insert(1,n,root[i-1],root[i]=++now,i,1);          
            else{ // 否则先在i插入 再在mp[a[i]]处反向插入,因为前面的个数不应该增加
                insert(1,n,root[i-1],root[i]=++now,i,1);                    
                int cid = ++now;    // 记录下新的树根
                insert(1,n,root[i],cid,mp[a[i]],-1);
                root[i] = cid;      // 原来的树根不要了 要更新好的树根
            }
            mp[a[i]] = i;   // 更新a[i]的位置
        }
        scanf("%d",&q);
        for(int i=1;i<=q;++i){
            scanf("%d%d",&l,&r);
            printf("%d
    ",query(root[r],l,r,1,n));  // 使用r的树根来查询
        }
        return 0;
    }
    

    有点想不通的是为什么最后的询问要用右端点的树来查询,而不能直接用最后一颗树查询(按理说后面的树不会更改前面树的信息吧...)

  • 相关阅读:
    bzoj1626[Usaco2007 Dec]Building Roads 修建道路*
    bzoj1610[Usaco2008 Feb]Line连线游戏*
    bzoj1666[Usaco2006 Oct]Another Cow Number Game 奶牛的数字游戏*
    bzoj1679[Usaco2005 Jan]Moo Volume 牛的呼声*
    bzoj1606[Usaco2008 Dec]Hay For Sale 购买干草*
    bzoj1264[AHOI2006]基因匹配Match
    bzoj4518[Sdoi2016]征途
    bzoj2049[Sdoi2008]Cave 洞穴勘测
    bzoj4514[Sdoi2016]数字配对
    bzoj2429[HAOI2006]聪明的猴子
  • 原文地址:https://www.cnblogs.com/xxrlz/p/11536136.html
Copyright © 2020-2023  润新知