spoj D-query 区间不同数个数 主席树||离线+树状数组
来源:互联网 发布:手机玩lol软件 编辑:程序博客网 时间:2024/04/28 13:08
把区间统计转化为前缀和,这里的前缀和不是普通的前缀和,对相同的ai,只有最右边那个才是有效的。
举个栗子:1 2 2 1 3 这样一个序列有效是这个样子 * * 2 1 3 ,因为1在后面出现过所以前一个无效,同理 2。前缀和则是0 0 1 2 3 ,那么对区间[1,5],[2,5],[3,5],[4,5],..[x,5] 我们都可以用sum[5]-sum[x-1]来求。
这里的一个问题是前缀和是对右端点确定的情况,所以只用一棵线段树或树状数组来维护的话就要离线,对查询的右端点进行排序。
如果强制在线怎么做呢,那就是主席树,简单理解为对每一个前缀建一棵线段树(这就是主席树做的事情),然后查询就是到右端点对应那棵树里去查询就ok了。
离线+树状数组
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <algorithm>#include <map>using namespace std;const int maxn=30000+5;map<int,int> mp;int data[maxn];int a[maxn];int ans[200000+5];struct node{ int l,r,id; bool operator<(node t)const{ return r<t.r; }}q[200000+5];int sum(int i){ int ans=0; while(i>0){ ans+=data[i]; i-=i&-i; } return ans;}void add(int i,int x){ while(i<maxn){ data[i]+=x; i+=i&-i; }}int main(){ int n; while(~scanf("%d",&n)){ fill(data,data+n+2,0); mp.clear(); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } int m; scanf("%d",&m); for(int i=0;i<m;i++){ scanf("%d%d",&q[i].l,&q[i].r); q[i].id=i; } sort(q,q+m); int pre=1; for(int i=0;i<m;i++){ for(int j=pre;j<=q[i].r;j++){ if(mp[a[j]]!=0){ add(mp[a[j]],-1); } add(j,1); mp[a[j]]=j; } pre=q[i].r+1; ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1); } for(int i=0;i<m;i++){ printf("%d\n",ans[i]); } } return 0;}
主席树
#include <iostream>#include <cstdio>#include <cstdlib>#include <cmath>#include <algorithm>#include <map>#define mid (l+r>>1)using namespace std;const int maxn=30000+5;int a[maxn],root[maxn];int data[maxn*20],ls[maxn*20],rs[maxn*20];int cnt;map<int,int> mp;int build(int l,int r){ int t=cnt++; data[t]=0; if(l==r)return t; ls[t]=build(l,mid); rs[t]=build(mid+1,r); return t;}int update(int p,int l,int r,int v,int w){ int t=cnt++; data[t]=data[p]+w; if(l==r) return t; if(v<=mid){ rs[t]=rs[p]; ls[t]=update(ls[p],l,mid,v,w); } else{ ls[t]=ls[p]; rs[t]=update(rs[p],mid+1,r,v,w); } return t;}int query(int t,int l,int r,int v){ if(l==r)return data[t]; if(v<=mid)return query(ls[t],l,mid,v)+data[rs[t]]; else return query(rs[t],mid+1,r,v);}int main(){ int n; while(~scanf("%d",&n)){ cnt=1;mp.clear(); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } root[0]=build(1,n); for(int i=1;i<=n;i++){ if(mp[a[i]]==0) root[i]=update(root[i-1],1,n,i,1); else { int tmp=update(root[i-1],1,n,mp[a[i]],-1); root[i]=update(tmp,1,n,i,1); } mp[a[i]]=i; } int m; scanf("%d",&m); for(int i=0;i<m;i++){ int l,r; scanf("%d%d",&l,&r); printf("%d\n",query(root[r],1,n,l)); } } return 0;}
0 0
- SPOJ D-query 区间不同数的个数 [在线主席树 or 离线树状数组]
- spoj D-query 区间不同数个数 主席树||离线+树状数组
- SPOJ DQUERY(树状数组离线处理 or 主席树 区间不同数个数)
- SPOJ 3267(DQUERY) D-query 【主席树】【离线树状数组】
- SPOJ D-query 树状数组离线&&主席树在线
- SPOJ3267 D-Query 树状数组离线操作 或 主席树 查询某一区间内有多少不同的数
- spoj 3267. D-query 主席树求区间不同数的个数
- spoj DQUERY - D-query(区间不同数的个数 主席树 or BIT)
- SPOJ D-query 主席树在线(求区间不同的数的个数)
- [spoj D-query] 主席树求区间不同数
- SPOJ 3267. D-query (主席树or树状数组离线)
- SPOJ D-query(区间不同的数的个数)
- SPOJ DQUERY 区间内不同数的个数 主席树
- SPOJ-DQUERY-主席树求区间不同数个数模板
- SPOJ DQUERY D-query 树状数组离线
- SPOJ D-query && HDU 3333 Turing Tree (线段树 && 区间不相同数个数or和 && 离线处理)
- [SPOJ 3267] D-query (离线询问+树状数组)
- SPOJ 3267. D-query (主席树,查询区间有多少个不相同的数)
- 开始博客之路
- 六种方式实现hibernate查询
- ViewTreeObserver
- RAC中Multicast的实现原理分析
- 程序设计进阶 编程题#4:Tomrrow never knows?
- spoj D-query 区间不同数个数 主席树||离线+树状数组
- 一个案例教你简单地玩转ViewPager(二)之ViewPaper+TabLayout+Fragment顶部标签界面滑动
- 我的感想
- 【op】tomcat部署服务器步骤
- Python 中的 None 与真假
- Eclipse下修改Android里的apk包名
- 斯坦福机器学习笔记-Lecture 1,2
- [完]Linux CentOS IP配置
- UntiyGUI系统之Image