SPOJ 3267(DQUERY) D-query 【主席树】【离线树状数组】

来源:互联网 发布:涂色 app 源码 编辑:程序博客网 时间:2024/03/28 20:34

题目链接
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 debugconst double PI=acos(-1.0);const int INF=0x3f3f3f3f;//1061109567-2147483647const long long LINF=0x3f3f3f3f3f3f3f3f;//4557430888798830399-9223372036854775807const 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\n",seq.answer(a,b));        }    }    return 0;}

树状数组离线

待更新……

0 0