zoukankan      html  css  js  c++  java
  • SPOJ 3267(DQUERY) D-query 【主席树】【离线树状数组】

    题目链接
    persistent segment tree

    题意

    给一串数列,有q个(1e5的数量级)询问,求i到j间的不同数字的个数

    分析

    这个题有几种做法,可以用主席树、离线树状数组,还可以直接用莫队。这里写一下主席树和离线树状数组的做法

    主席树做法

    若用线段树,父子节点之间存的状态不好合并,这时先考虑一个简化的问题:对于一个序列,它的某个前缀有多少个不同的数?
    此时,既然起始位置已经定了下来,那么对于序列中同样的一个数,必定只需要记录前面那个数就行了。这个问题就可以把所有数第一次出现的位置用线段树维护起来解决。
    既然前缀如此,后缀也类似,只不过总是记录最晚出现的位置。而任意一个区间都可以看作以某个数为结尾的后缀,这时,我们只需要把原序列按每个数作为后缀的起点来建立n棵线段树,从而快速求得区间中不同数的个数。为了节约空间,自然要用主席树来解决。

    离线树状数组做法

    待更新……

    AC代码

    主席树

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cctype>
    #include <cstdlib>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <string>
    #include <map>
    #include <queue>
    #include <deque>
    #include <list>
    #include <sstream>
    #include <stack>
    using namespace std;
    
    #define cls(x) memset(x,0,sizeof x)
    #define inf(x) memset(x,0x3f,sizeof x)
    #define neg(x) memset(x,-1,sizeof x)
    #define ninf(x) memset(x,0xc0,sizeof x)
    #define st0(x) memset(x,false,sizeof x)
    #define st1(x) memset(x,true,sizeof x)
    #define lowbit(x) x&(-x)
    #define input(x) scanf("%d",&(x))
    #define inputt(x,y) scanf("%d %d",&(x),&(y))
    #define bug cout<<"here"<<endl;
    //#pragma comment(linker, "/STACK:1024000000,1024000000")//stack expansion
    //#define debug
    const double PI=acos(-1.0);
    const int INF=0x3f3f3f3f;//1061109567-2147483647
    const long long LINF=0x3f3f3f3f3f3f3f3f;//4557430888798830399-9223372036854775807
    const int maxn=300000+1000;
    
    int a[maxn];
    int n,q;
    
    /* 主席树 */
    struct chairNode
    {
        int sum;
        int ls,rs;
    };
    
    struct chairmanTree
    {
        chairNode tree[maxn*20];
        int root[maxn];
        size_t tsize;
        map<int,int> occur;
        int left,right;
        void Push_Up(int x)
        {
            tree[x].sum=tree[tree[x].ls].sum+tree[tree[x].rs].sum;
            return;
        }
        /* 建树 */
        void build(int n,int L,int R)
        {
            left=L;right=R;
            cls(root);
            tsize=1;
            tree[0].ls=tree[0].rs=tree[0].sum=0;//零结点要指向自己
            occur.clear();
            for(int i=1;i<=n;++i)
            {
                if(occur.count(a[i]))
                    root[i]=insert(insert(root[i-1],occur[a[i]],L,R,-1),i,L,R,1);
                else
                    root[i]=insert(root[i-1],i,L,R,1);
                occur[a[i]]=i;
            }
            return;
        }
        /* 插入结点 */
        int insert(int x,int pos,int L,int R,int v)
        {
            tree[tsize++]=tree[x];
            x=tsize-1;
            if(L==R)
            {
                tree[x].sum+=v;
                return x;
            }
            int mid=(L+R)>>1;
            if(pos<=mid)
                tree[x].ls=insert(tree[x].ls,pos,L,mid,v);
            else
                tree[x].rs=insert(tree[x].rs,pos,mid+1,R,v);
            Push_Up(x);
            return x;
        }
        int answer(int start,int endd)
        {
            return query(root[endd],start,left,right);
        }
        int query(int x,int pos,int L,int R)
        {
            if(L==pos&&R==pos)
                return tree[x].sum;
            int mid=(L+R)>>1;
            if(pos<=mid)
                return query(tree[x].ls,pos,L,mid)+tree[tree[x].rs].sum;
            else
                return query(tree[x].rs,pos,mid+1,R);
        }
    }seq;
    
    int main()
    {
        //ios::sync_with_stdio(false);
        //cin.tie(0);
        #ifdef debug
            freopen("E:\Documents\code\input.txt","r",stdin);
            freopen("E:\Documents\code\output.txt","w",stdout);
        #endif
        //IO
        while(input(n)!=EOF)
        {
            for(int i=1;i<=n;++i)
                input(a[i]);
            input(q);
            seq.build(n,1,n);
            int a,b;
            while(q--)
            {
                inputt(a,b);
                printf("%d
    ",seq.answer(a,b));
            }
        }
        return 0;
    }

    树状数组离线

    待更新……

  • 相关阅读:
    RQNOJ 342 最不听话的机器人:网格dp
    RQNOJ 329 刘翔!加油!:01背包
    RQNOJ 57 找啊找啊找GF:01背包
    RQNOJ 202 奥运火炬登珠峰:01背包
    RQNOJ 201 奥运大包围:LIS + 拼链成环
    2017SN多校D1T2 note:dp
    2017SN多校D1T1 loveletter:模拟
    HDU 2157 How many ways??:矩阵快速幂【i到j共经过k个节点的方法数】
    poj 3764 The xor-longest Path
    bzoj 1192 鬼谷子的钱袋
  • 原文地址:https://www.cnblogs.com/DrCarlluo/p/6580582.html
Copyright © 2011-2022 走看看