学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))
2016-02-05 14:39
405 查看
函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同…
那么原理也比较易懂:
建造一棵线段树(权值线段树),维护的信息是序列中每个数的出现次数,静态查询第K极值,只需要从根做二分,然后向下转左右子树,找到叶子节点即可…(由于线段树的性质,这个查找的复杂度是log级..)
那么动态的第K极值呢..
需要用上树状数组,这时树状数组维护的其实就是一串主席树了,不过这样处理,会MLE,但是应用可持久化原理,每次修改,对于线段树来说,只是修改了一个叶子点到根的路径,其余的路径都是不变的,所以每次只需要保存一条路径即可咯,但是如何找到那样的数 呢….此处应用前缀和操作,r和l-1的差值即为l~r的值,所以用同样原理,应用树状数组维护即可..代码量会降低..
动态维护模板(ZOJ2112)
那么原理也比较易懂:
建造一棵线段树(权值线段树),维护的信息是序列中每个数的出现次数,静态查询第K极值,只需要从根做二分,然后向下转左右子树,找到叶子节点即可…(由于线段树的性质,这个查找的复杂度是log级..)
那么动态的第K极值呢..
需要用上树状数组,这时树状数组维护的其实就是一串主席树了,不过这样处理,会MLE,但是应用可持久化原理,每次修改,对于线段树来说,只是修改了一个叶子点到根的路径,其余的路径都是不变的,所以每次只需要保存一条路径即可咯,但是如何找到那样的数 呢….此处应用前缀和操作,r和l-1的差值即为l~r的值,所以用同样原理,应用树状数组维护即可..代码量会降低..
动态维护模板(ZOJ2112)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; #define MAXN 60010 #define M 2500010 int n,q,m,tot; int a[MAXN],t[MAXN]; int T[MAXN],lc[M],rc[M],c[M]; int S[MAXN]; struct data{ int kind;int l,r,k; }query[10010]; void init_hash(int num) { sort(t,t+num); m=unique(t,t+num)-t; } int hash(int x) { return lower_bound(t,t+m,x)-t; } int build(int l,int r) { int root=tot++; c[root]=0; if (l!=r) { int mid=(l+r)/2; lc[root]=build(l,mid); rc[root]=build(mid+1,r); } return root; } int insert(int root,int pos,int val) { int newroot=tot++,tmp=newroot; int l=0,r=m-1; c[newroot]=c[root]+val; while (l<r) { int mid=(l+r)>>1; if (pos<=mid) { lc[newroot]=tot++; rc[newroot]=rc[root]; newroot=lc[newroot]; root=lc[root]; r=mid; } else { rc[newroot]=tot++; lc[newroot]=lc[root]; newroot=rc[newroot]; root=rc[root]; l=mid+1; } c[newroot]=c[root]+val; } return tmp; } int lowbit(int x){return x&(-x);} int use[MAXN]; void add(int x,int pos,int val) { while (x<=n) { S[x]=insert(S[x],pos,val); x+=lowbit(x); } } int sum(int x) { int re=0; while (x>0) { re+=c[lc[use[x]]]; x-=lowbit(x); } return re; } int Query(int L,int R,int k) { int l_root=T[L-1]; int r_root=T[R]; int l=0,r=m-1; for (int i=L-1; i; i-=lowbit(i)) use[i]=S[i]; for (int i=R; i; i-=lowbit(i)) use[i]=S[i]; while (l<r) { int mid=(l+r)>>1; int tmp=sum(R)-sum(L-1)+c[lc[r_root]]-c[lc[l_root]]; if (tmp>=k) { r=mid; for (int i=L-1; i; i-=lowbit(i)) use[i]=lc[use[i]]; for (int i=R; i; i-=lowbit(i)) use[i]=lc[use[i]]; l_root=lc[l_root]; r_root=lc[r_root]; } else { l=mid+1;k-=tmp; for (int i=L-1; i; i-=lowbit(i)) use[i]=rc[use[i]]; for (int i=R; i; i-=lowbit(i)) use[i]=rc[use[i]]; l_root=rc[l_root]; r_root=rc[r_root]; } } return l; } void Modify(int x,int p,int d) { while (x<=n) { S[x]=insert(S[x],p,d); x+=lowbit(x); } } int main() { int test; scanf("%d",&test); while (test--) { scanf("%d%d",&n,&q); tot=0;m=0; for (int i=1; i<=n; i++) { scanf("%d",&a[i]); t[m++]=a[i]; } char opt[10]; for (int i=0; i<q; i++) { scanf("%s",opt); if (opt[0]=='Q') { query[i].kind=0; scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k); } else { query[i].kind=1; scanf("%d%d",&query[i].l,&query[i].r); t[m++]=query[i].r; } } init_hash(m); T[0]=build(0,m-1); for (int i=1; i<=n; i++) T[i]=insert(T[i-1],hash(a[i]),1); for (int i=1; i<=n; i++) S[i]=T[0]; for (int i=0; i<q; i++) { if (query[i].kind==0) printf("%d\n",t[Query(query[i].l,query[i].r,query[i].k)]); else { Modify(query[i].l,hash(a[query[i].l]),-1); Modify(query[i].l,hash(query[i].r),1); a[query[i].l]=query[i].r; } } } return 0; }
相关文章推荐
- 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))
- B - Open the lightings (组合数学)
- 浅析linux上如何让apache运行aspx网站即asp.net代码
- shell比较两个字符串是否相等
- VS2013: Intellisense cannot open source file “*.h”
- 监控apache虚拟主机进程
- linux命令行下如何以目录树的形式显示一个文件夹的所有文件
- hadoop中的一些概念——数据流
- 棋牌游戏服务器架构: 详细设计(二) 应用层设计
- 基于InfluxDB&Grafana的JMeter实时性能测试数据的监控和展示
- 棋牌游戏服务器架构: 详细设计(一) 内核设计
- 棋牌游戏服务器架构: 部署
- 棋牌游戏服务器架构: 总体设计
- video : Write and Submit your first Linux kernel Patch
- 达观数据搜索引擎的Query自动纠错技术和架构
- HD 1011 Starship Troopers(树上的背包)
- Linux相关问题-CentOS6.5 x64版本号下Tomcat无法自启动的解决的方法
- linux 免交互状态下修改用户密码
- usaco 3.3 shopping 2008.11.7
- Tomcat配置环境变量