SPOJ 3267(DQUERY) D-query 【主席树】【离线树状数组】
2016-10-26 19:44
204 查看
题目链接
persistent segment tree
此时,既然起始位置已经定了下来,那么对于序列中同样的一个数,必定只需要记录前面那个数就行了。这个问题就可以把所有数第一次出现的位置用线段树维护起来解决。
既然前缀如此,后缀也类似,只不过总是记录最晚出现的位置。而任意一个区间都可以看作以某个数为结尾的后缀,这时,我们只需要把原序列按每个数作为后缀的起点来建立n棵线段树,从而快速求得区间中不同数的个数。为了节约空间,自然要用主席树来解决。
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\n",seq.answer(a,b)); } } return 0; }
树状数组离线
待更新……相关文章推荐
- SPOJ3267 D-query 离线+树状数组 在线主席树
- spoj D-query 区间不同数个数 主席树||离线+树状数组
- SPOJ DQUERY(树状数组离线处理 or 主席树 区间不同数个数)
- SPOJ3267--D-query (树状数组离线操作)
- SPOJ D-query 区间不同数的个数 [在线主席树 or 离线树状数组]
- [SPOJ DQUERY] D-query(树状数组,离线)
- SPOJ DQUERY (离线数状数组||在线主席树)
- D-query SPOJ - DQUERY (树状数组离线预处理||主席树)
- SPOJ3267 D-Query 树状数组离线操作 或 主席树 查询某一区间内有多少不同的数
- SPOJ 3267: DQUERY 树状数组,离线算法
- SPOJ DQUERY (离线数状数组||在线主席树)
- SPOJ - DQUERY :D-query(主席树或离线)
- SPOJ DQUUERY (在线主席树 | 离线树状数组)
- SPOJ 3267. D-query (主席树,查询区间有多少个不相同的数)
- bzoj 1901: Zju2112 Dynamic Rankings(离线树状数组+主席树)
- [广义后缀自动机 set启发式合并 || dfs序 树状数组 离线] BZOJ 2780 [Spoj]8093 Sevenk Love Oimaster
- [区间GCD预处理 树状数组 离线] HDU 5869 Different GCD Subarray Query
- 【主席树|莫队|离线树状数组】BZOJ1878 [SDOI 2009]HH的项链
- SPOJ DQUERY 练习赛 (主席树数组模板)
- [离线+树状数组 || 主席树]BZOJ1878: [SDOI2009]HH的项链