2017-10-19数据结构学习
来源:互联网 发布:工程预算软件手机版 编辑:程序博客网 时间:2024/06/03 15:37
BIT求LCA
#include<cstdio>#include<algorithm>using namespace std;#define M 1005int n;int B[M],A[M],C[M];int query(int x){ int ans=0; while(x){ ans=max(ans,B[x]); x-=x&(-x); } return ans;}void update(int x,int a){ while(x<=n){ B[x]=max(B[x],a); x+=x&(-x); }}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&A[i]); C[i]=A[i]; } sort(C+1,C+n+1); int len=unique(C+1,C+n+1)-C-1; for(int i=1;i<=n;i++){ int x=lower_bound(C+1,C+len+1,A[i])-C; int res=query(x-1); update(x,res+1); } printf("%d\n",query(n)); return 0;}
分块+二分 求区间第K大值
对于第k大值,并不知道是什么
但由于满足单调性,可以二分答案,复杂度为
把数列分割成多个块 设块的长度为S
询问时同理在块中二分查找,在块外for循环,复杂度大概是
为了使复杂度最小 S取
代码实现:
#include<cstdio>#include<algorithm>#include<cmath>using namespace std;#define FOR(i,x,y) for(int i=(x);i<=(y);i++)#define M 30005#define QM 200int A[M];int B[QM][M],Len[QM];int S,T;int n,m,mx=0;void init(){ for(int k=1;k<=T;k++){ int len=min(n,S*k); for(int i=1+S*(k-1);i<=len;i++){ B[k][i-S*(k-1)]=A[i]; } len=len-S*(k-1); Len[k]=len; sort(B[k]+1,B[k]+len+1); }}int query(int l,int r,int res){// r-l+1-ans; int ans=0; int L=(l-1)/S+1,R=(r-1)/S+1; if(L==R)for(int i=l;i<=r;i++){ if(A[i]<res)ans++; } else { for(int i=l;i<=S*L;i++)if(A[i]<res)ans++; for(int i=(R-1)*S+1;i<=r;i++)if(A[i]<res)ans++; for(int i=L+1;i<=R-1;i++){ ans+=lower_bound(B[i]+1,B[i]+Len[i]+1,res)-B[i]-1; } } return r-l+1-ans;}int main(){ scanf("%d%d",&n,&m); FOR(i,1,n){ scanf("%d",&A[i]); if(mx<A[i])mx=A[i]; } S=sqrt(n*log2(n)); T=(n-1)/S+1; init(); FOR(i,1,m){ int L,R,k; scanf("%d%d%d",&L,&R,&k); int l=1,r=mx,res; while(l<=r){ int mid=(l+r)>>1; if(query(L,R,mid)>=k)l=mid+1,res=mid; else r=mid-1; } printf("%d\n",res); } return 0;}
归并树+二分 求区间第K大值
听大佬说一般用不到。。。
建树时顺便归并,复杂度为
同样二分在询问一个数在区间内在第几位
在树中询问一个数在第几位使用二分查找复杂度为
所以整个询问的复杂度为
在加上二分整个题目的复杂度为
而空间复杂度为
代码实现:
#include<cstdio>#include<algorithm>using namespace std;#define FOR(i,x,y) for(int i=(x);i<=(y);i++)#define S 200#define N 30005int B[S][N];int A[N];struct Tree{int l,r;}tree[N<<2];void build(int l,int r,int p,int dep){ tree[p].l=l,tree[p].r=r; if(l==r){ B[dep][l]=A[l]; return; } int mid=(l+r)>>1; build(l,mid,p<<1,dep+1); build(mid+1,r,p<<1|1,dep+1); int a1=l,a2=mid+1,cnt=l-1; while(a1<=mid&&a2<=r){ if(B[dep+1][a1]<B[dep+1][a2])B[dep][++cnt]=B[dep+1][a1],a1++; else B[dep][++cnt]=B[dep+1][a2],a2++; } while(a1<=mid)B[dep][++cnt]=B[dep+1][a1],a1++; while(a2<=r)B[dep][++cnt]=B[dep+1][a2],a2++;}int query(int l,int r,int k,int p,int dep){ if(tree[p].l==l&&tree[p].r==r){ return lower_bound(B[dep]+l,B[dep]+r+1,k)-B[dep]-l; } int mid=(tree[p].r+tree[p].l)>>1; if(mid>=r)return query(l,r,k,p<<1,dep+1); else if(mid<l)return query(l,r,k,p<<1|1,dep+1); else return query(l,mid,k,p<<1,dep+1)+query(mid+1,r,k,p<<1|1,dep+1);}int main(){ int n,m,mx=0; scanf("%d%d",&n,&m); FOR(i,1,n){ scanf("%d",&A[i]); if(mx<A[i])mx=A[i]; } build(1,n,1,1); FOR(i,1,m){ int L,R,k; scanf("%d%d%d",&L,&R,&k); int l=1,r=mx,res; while(l<=r){ int mid=(l+r)>>1; int d=R-L+1-query(L,R,mid,1,1); if(d>=k){ l=mid+1; res=mid; } else r=mid-1; } printf("%d\n",res); } return 0;}
主席树+二分 求区间第K大值
学了那么久这个才是重头戏
静态主席树的实现:(感觉下面这段话说得很清楚了)
首先静态主席树这个东西其实比较好懂,就是对于每个前缀[1,1],[1,2]….[1,n]都建一颗线段树,将数据离散化后,在线段树中统计区间内所有值出现的次数,每一个线段树都是相同的形态,那么这样我们得到一个很好的性质,这些线段树可以“相减”,假设当前查询的是区间[l,r]内第k大的值,那么我们用前缀[1, r]这个线段树和前缀[1,l-1]这颗线段树通过相减加上二分就可以找到答案。由于相邻两颗线段树最多只有logn个节点不同,我们没有必要完全新建一颗线段树,只需要把相同的结点用指针指一下就行,然后新建logn个结点,这样一来时空复杂度为n*logn。
实现 我好意思说自己是copy的吗???
#include<cstdio>#include<algorithm>using namespace std;#define FOR(i,x,y) for(int i=(x);i<=(y);i++)#define M 30005#define S 20int lson[M*S],rson[M*S],Sum[M*S],tot,tree[M];int A[M],B[M];void build(int l,int r,int &tid){ tid=++tot; Sum[tid]=0; if(l==r)return; int mid=(l+r)>>1; build(l,mid,tid); build(mid+1,r,tid);}void insert(int l,int r,int x,int ot,int &tid){ tid=++tot; lson[tid]=lson[ot]; rson[tid]=rson[ot]; Sum[tid]=Sum[ot]+1; if(l==r)return; int mid=(l+r)>>1; if(x<=mid)insert(l,mid,x,lson[ot],lson[tid]); else insert(mid+1,r,x,rson[ot],rson[tid]);}int query(int lt,int rt,int L,int R,int k){ if(L==R)return L; int mid=(L+R)>>1; int cnt=Sum[lson[rt]]-Sum[lson[lt]]; if(cnt>=k)return query(lson[lt],lson[rt],L,mid,k); else return query(rson[lt],rson[rt],mid+1,R,k-cnt);}int main(){ int n,m; scanf("%d%d",&n,&m); FOR(i,1,n)scanf("%d",&A[i]),B[i]=A[i]; sort(B+1,B+1+n); int len=unique(B+1,B+1+n)-B-1; build(1,len,tree[0]); FOR(i,1,n){ int x=lower_bound(B+1,B+len+1,A[i])-B; insert(1,len,x,tree[i-1],tree[i]); } FOR(i,1,m){ int l,r,k; scanf("%d%d%d",&l,&r,&k); printf("%d\n",B[query(tree[l-1],tree[r],1,len,r-l+2-k)]); } return 0;}
阅读全文
1 0
- 2017-10-19数据结构学习
- 《数据结构》学习笔记 19-20
- 学习 严蔚敏讲数据结构笔记19
- 2008.09.10数据结构学习笔记
- 学习 严蔚敏讲数据结构笔记10
- 数据结构学习
- 数据结构学习
- 数据结构学习
- 数据结构学习
- 数据结构学习
- 数据结构学习
- 学习数据结构
- 数据结构学习
- 数据结构学习
- 数据结构学习
- 数据结构 学习
- 数据结构学习
- 数据结构学习
- 通知Notification小记
- HTTP头的查看
- 机器学习方向的相关的分析
- 编码规范
- iOS- NSThread/NSOperation/GCD 三种多线程技术的对比及实现
- 2017-10-19数据结构学习
- SpringMVC入门及系列教程(四)-SpringMVC在控制器中获取请求中的参数值(详细)
- 数据结构 第9讲 数组与广义表
- C操作符总结
- 单行居中,多行居左
- JAVA最新中国手机号段匹配
- 可跨域的单点登录(SSO)实现方案【附.net代码】
- 关于clear和浮动
- Linux的单用户模式、救援模式、克隆虚拟机、机器相互登录