SPOJ DQUERY (离线数状数组||在线主席树)
2013-02-01 12:59
302 查看
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents
by---cxlove
题目:给出一个序列,查询区间内有多少个不同的树
链接:http://www.spoj.com/problems/DQUERY/
跟 着岛娘,适妞一起学主席树。。。
解法一:离线做法
将查询区间按左端点排序
对于相同的数,先更新最左边的位置
然后根据查询区间,不断更新next,保证查询区间内
只更新过一个位置
维护前缀和用树状数组,时空效率都高
解法二:在线做法
对于每一个起始位置,都建立一棵主席树
从后往前更新,更新的时候就是在next位置先减掉,然后更新在当前位置。
主席树又称为可持久化线段树,其本质上是保存了所有的历史信息。
也可以理解为多棵线段树,在更新的时候,充分共同利用历史信息
对于点更新来说,更新的总是某一棵子树,另外一棵子树,则指向原来的结点即可。
可是即使如此,主席树还是需要大量的空间。
by---cxlove
题目:给出一个序列,查询区间内有多少个不同的树
链接:http://www.spoj.com/problems/DQUERY/
跟 着岛娘,适妞一起学主席树。。。
解法一:离线做法
将查询区间按左端点排序
对于相同的数,先更新最左边的位置
然后根据查询区间,不断更新next,保证查询区间内
只更新过一个位置
维护前缀和用树状数组,时空效率都高
int s ,a ; int n,q,ans[M]; int nxt ; map<int,int >mp; struct Question{ int l,r,id; bool operator<(const Question q)const{ return l<q.l; } }Q[M]; void add(int x,int val){ for(int i=x;i<=n;i+=lowbit(i)) s[i]+=val; } int query(int x){ int ret=0; for(int i=x;i>0;i-=lowbit(i)) ret+=s[i]; return ret; } int main(){ while(scanf("%d",&n)!=EOF){ mp.clear(); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(mp.find(a[i])==mp.end()){ mp[a[i]]=i; add(i,1); } } mp.clear(); for(int i=n;i;i--){ if(mp.find(a[i])==mp.end()) nxt[i]=n+1; else nxt[i]=mp[a[i]]; mp[a[i]]=i; } scanf("%d",&q); for(int i=0;i<q;i++){ scanf("%d%d",&Q[i].l,&Q[i].r); Q[i].id=i; } sort(Q,Q+q); int t=1; for(int i=0;i<q;i++){ while(t<=n&&t<Q[i].l) add(nxt[t++],1); ans[Q[i].id]=query(Q[i].r)-query(Q[i].l-1); } for(int i=0;i<q;i++) printf("%d\n",ans[i]); } return 0; }
解法二:在线做法
对于每一个起始位置,都建立一棵主席树
从后往前更新,更新的时候就是在next位置先减掉,然后更新在当前位置。
主席树又称为可持久化线段树,其本质上是保存了所有的历史信息。
也可以理解为多棵线段树,在更新的时候,充分共同利用历史信息
对于点更新来说,更新的总是某一棵子树,另外一棵子树,则指向原来的结点即可。
可是即使如此,主席树还是需要大量的空间。
map<int,int>mp; int a ,tot,n,q; int T[M],lson[M],rson[M],val[M]; int bulid(int l,int r){ int root=tot++; val[root]=0; int m=(l+r)>>1; if(l!=r){ lson[root]=bulid(l,m); rson[root]=bulid(m+1,r); } return root; } int update(int root,int pos,int v){ int newroot=tot++,tmp=newroot; int l=1,r=n; val[newroot]=val[root]+v; while(l<r){ int m=(l+r)>>1; //更新的时候需要充分利用历史信息 //更新原来的左子树,右子树不变 if(pos<=m){ lson[newroot]=tot++;rson[newroot]=rson[root]; newroot=lson[newroot];root=lson[root]; r=m; } //更新右子树 else{ rson[newroot]=tot++;lson[newroot]=lson[root]; newroot=rson[newroot];root=rson[root]; l=m+1; } val[newroot]=val[root]+v; } return tmp; } int query(int root,int pos){ int ret=0; int l=1,r=n; while(pos<r){ int m=(l+r)>>1; if(pos<=m){ r=m; root=lson[root]; } else{ ret+=val[lson[root]]; root=rson[root]; l=m+1; } } return ret+val[root]; } int main(){ while(scanf("%d",&n)!=EOF){ tot=0; //结点数 for(int i=1;i<=n;i++) scanf("%d",&a[i]); T[n+1]=bulid(1,n); for(int i=n;i;i--){ int nxt; map<int,int>::iterator it=mp.find(a[i]); if(it==mp.end()) nxt=n+1; else nxt=it->second; //如果这是第一次出现,也就是最后一个位置上,则直接更新 if(nxt>n) T[i]=update(T[i+1],i,1); //在原来的位置上擦掉,在当前位置更新 else{ int t=update(T[i+1],nxt,-1); T[i]=update(t,i,1); } mp[a[i]]=i; } scanf("%d",&q); while(q--){ int l,r; scanf("%d%d",&l,&r); printf("%d\n",query(T[l],r)); } } return 0; }
相关文章推荐
- SPOJ DQUERY (离线数状数组||在线主席树)
- SPOJ3267 D-query 离线+树状数组 在线主席树
- SPOJ D-query 区间不同数的个数 [在线主席树 or 离线树状数组]
- SPOJ DQUERY(树状数组离线处理 or 主席树 区间不同数个数)
- SPOJ 3267(DQUERY) D-query 【主席树】【离线树状数组】
- spoj D-query 区间不同数个数 主席树||离线+树状数组
- SPOJ3267--D-query(离线线段树||在线主席树)
- [SPOJ DQUERY] D-query(树状数组,离线)
- D-query SPOJ - DQUERY (树状数组离线预处理||主席树)
- SPOJ - DQUERY :D-query(主席树或离线)
- SPOJ D-query 树状数组离线&&主席树在线
- SPOJ DQUERY 练习赛 (主席树数组模板)
- SPOJ DQUUERY (在线主席树 | 离线树状数组)
- SPOJ3267--D-query (树状数组离线操作)
- SPOJ D-query 主席树在线(求区间不同的数的个数)
- SPOJ3267 D-Query 树状数组离线操作 或 主席树 查询某一区间内有多少不同的数
- SPOJ 3267 DQUERY(主席树在线|树状数组离线)
- SPOJ - DQUERY 主席树
- [区间GCD预处理 树状数组 离线] HDU 5869 Different GCD Subarray Query
- SPOJ DQUERY D-query(离线线段树,查区间不同数字个数)