SPOJ DQUERY (离线数状数组||在线主席树)
来源:互联网 发布:安知鸿鹄之志哉全文 编辑:程序博客网 时间:2024/04/28 21:26
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:给出一个序列,查询区间内有多少个不同的树
链接:http://www.spoj.com/problems/DQUERY/
跟 着岛娘,适妞一起学主席树。。。
解法一:离线做法
将查询区间按左端点排序
对于相同的数,先更新最左边的位置
然后根据查询区间,不断更新next,保证查询区间内
只更新过一个位置
维护前缀和用树状数组,时空效率都高
int s[N],a[N];int n,q,ans[M];int nxt[N];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[N],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 (离线数状数组||在线主席树)
- SPOJ DQUERY (离线数状数组||在线主席树)
- SPOJ 3267 DQUERY(主席树在线|树状数组离线)
- SPOJ DQUERY(树状数组离线处理 or 主席树 区间不同数个数)
- SPOJ DQUERY树状数组离线or主席树
- SPOJ 3267(DQUERY) D-query 【主席树】【离线树状数组】
- SPOJ DQUERY 离线树状数组or主席树
- SPOJ - DQUERY 【主席树】
- SPOJ D-query 区间不同数的个数 [在线主席树 or 离线树状数组]
- SPOJ DQUUERY (在线主席树 | 离线树状数组)
- SPOJ D-query 树状数组离线&&主席树在线
- SPOJ DQUERY 入门主席树
- SPOJ DQUERY 区间内不同数的个数 主席树
- SPOJ-DQUERY-主席树求区间不同数个数模板
- SPOJ DQUERY 练习赛 (主席树数组模板)
- spoj DQUERY D-query SPOJ -(主席树)
- SPOJ DQUERY D-query 树状数组离线
- SPOJ DQUERY 主席树+lazy+乱搞
- float在内存中的表示
- 风险指针(Hazard Pointers)——用于无锁对象的安全内存回收机制
- c#中往mysql里批量插入上万条数据
- 黑马程序员-Java基础加强-反射
- Axure RP Pro 6.5.0.3037 简体中文/正体中文加强正式版 2012-9-30 中秋版 发布
- SPOJ DQUERY (离线数状数组||在线主席树)
- 类成员初始化
- C#大量函数
- linux批量修改文件内容, 多目录重命名文件
- QT & SQLite - driver not loaded[Win7 XP mode failed too]
- 我的第一个 hello java
- Java 7 的新特性一览表
- 【 小白篇】Eclipse之 JUnit Test Cast [JUnit 4]
- java swing和swt背后的故事