ZOJ 2112 Dynamic Rankings BIT套ChairTree
来源:互联网 发布:哪个软件可以看黄子片 编辑:程序博客网 时间:2024/06/05 07:50
劳资就是想单纯的测个模板,怎么就特喵的这么难。
首先说一下自己对主席树的理解。
作用:确定区间[L,R]内的第K大数,或者区间内有多少个不同个元素。
主席树的另一个名字叫做函数式线段树,然后我查了一下函数式的特点,其中之一就是不修改状态。
从主席树上来看这个特点就是:在向主席树插入第 i 个元素之后,我们仍能查询到没插入 i 之前的状态。
主席树的构造:
对于有n个元素,s个不同元素的区间,对应的主席树CT 是由n 棵线段树组成的 ,对于第 i 棵线段树记录[1,i]区间内s个元素出现的次数。
那么当查询[L,R](1<= L <= R <= n,1 <= k <= R-L+1)内第K大数,我们需要讨论[1,L-1] ,[1,R]内各个元素的出现次数之差。
1.最开始时l = 1,r = s,;
2.mid = (l+r)>>1,如果[1,L-1],[1,R] 两者的[l,mid]的出现之差大于等于k,答案肯定在[l,mid],否则肯定在[mid+1,r]。
3.更新l,r,如果l == r,算法结束,答案就是s个元素中的第 r 大的数。否则转步骤二。
一些优化:
如果我们对于每个节点都要去建立一棵线段树,那么复杂度为n*s*log(s)。
但是分析一下会发现第i-1棵与第 i 棵线段树只会有log(s)个元素不一样,也就是第 i 个元素插入时造成的差异,那么我们只需要新开辟log(s)个节点,其它节点第i-1棵与第 i 棵线段树共用就好了。这样就降到了n*log(s)。
但是这样是没有办法进行高效的更新的。
很幸运的是我们一直在用区间作差的方法来查询结果,那么一个很显然的想法就是在ChairTree外面套一层BIT,使得一次查询和更新的复杂度都到了log(n)*log(s)。
空间复杂度升到了(n+m)*log(n)*log(s)。
然后这个题就解决了。
#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <queue>#include <cmath>#include <algorithm>#include <string>#define LL long long#define EPS (1e-8)#define INF 0x3f3f3fusing namespace std;const int MAXQ = 10010;const int MAXN = 50010;const int MAXLOG = 16;int num[MAXN],uni[MAXN+MAXQ];int siz;inline int lowbit(int x){ return x&(-x);}int DelSame(int *num,int n){ sort(uni+1,uni+n+1); int i,j; for(j = 1,i = 2; i <= n; ++i) if(num[i] != num[j]) num[++j] = num[i]; return j;}struct ChairTree{ int l,r; int ans;} ct[MAXQ*MAXLOG*MAXLOG];int ctRootofBIT[MAXN];int ctRoot[MAXN];int ctTop;int LIndex[MAXLOG],RIndex[MAXLOG];int CalSite(int x,int L,int R,int *uni){ int mid; while(L <= R) { mid = (L+R)>>1; if(x == uni[mid]) return mid; if(x < uni[mid]) R = mid-1; else L = mid+1; } return -1;}int InitZeroLayer(int l,int r){ if(l == r) { ct[ctTop].l = -1,ct[ctTop].r = -1; ct[ctTop].ans = 0; return ctTop++; } int mid = (l+r)>>1; int root = ctTop++; ct[root].ans = 0; ct[root].l = InitZeroLayer(l,mid); ct[root].r = InitZeroLayer(mid+1,r); return root;}int InitIthLayer(int pre,int l,int r,int goal){ if(l == r) { ct[ctTop].l = -1,ct[ctTop].r = -1; ct[ctTop].ans = ct[pre].ans+1; return ctTop++; } int mid = (l+r)>>1,root = ctTop++; ct[root] = ct[pre]; if(goal <= mid) ct[root].l = InitIthLayer(ct[pre].l,l,mid,goal); else ct[root].r = InitIthLayer(ct[pre].r,mid+1,r,goal); ct[root].ans = ct[ct[root].l].ans + ct[ct[root].r].ans; return root;}void InitChairTree(int n,int siz){ ctTop = 0; ctRoot[0] = InitZeroLayer(1,siz); int i,tmp; for(i = 1; i <= n; ++i) ctRoot[i] = InitIthLayer(ctRoot[i-1],1,siz,tmp = CalSite(num[i],1,siz,uni));}int QueryOnChairTree(int L,int R,int k,int l,int r){ if(l == r) return uni[r]; int mid = (l+r)>>1; if(ct[ct[R].l].ans - ct[ct[L].l].ans >= k) return QueryOnChairTree(ct[L].l,ct[R].l,k,l,mid); return QueryOnChairTree(ct[L].r,ct[R].r,k-(ct[ct[R].l].ans - ct[ct[L].l].ans),mid+1,r);}void InitChairTreeInBIT(int n){ memset(ctRootofBIT,-1,sizeof(int)*(n+2));}void UpdateIthLayerCTInBIT(int &root,int L,int R,int k,int data){ if(root == -1) { ct[ctTop].l = -1; ct[ctTop].r = -1; ct[ctTop].ans = 0; root = ctTop++; } if(L == R) { ct[root].ans += data; return ; } int mid = (L+R)>>1; if(k <= mid) UpdateIthLayerCTInBIT(ct[root].l,L,mid,k,data); else UpdateIthLayerCTInBIT(ct[root].r,mid+1,R,k,data); ct[root].ans = 0; if(ct[root].l != -1) ct[root].ans += ct[ct[root].l].ans; if(ct[root].r != -1) ct[root].ans += ct[ct[root].r].ans;}void UpdateChairTreeInBIT(int site,int data,int n){ int tr = site,k = CalSite(num[site],1,siz,uni); while(tr <= n) { UpdateIthLayerCTInBIT(ctRootofBIT[tr],1,siz,k,-1); tr += lowbit(tr); } num[site] = data; tr = site,k = CalSite(data,1,siz,uni); while(tr <= n) { UpdateIthLayerCTInBIT(ctRootofBIT[tr],1,siz,k,1); tr += lowbit(tr); }}int GiveMetheAnwser(int LTop,int RTop,int Lroot,int Rroot,int k,int L,int R){ if(L == R) return uni[L]; int mid = (L+R)>>1,i,tr,tl,ans = ct[ct[Rroot].l].ans-ct[ct[Lroot].l].ans; for(i = 0; i < RTop; ++i) if(ct[RIndex[i]].l != -1) ans += ct[ct[RIndex[i]].l].ans; for(i = 0; i < LTop; ++i) if(ct[LIndex[i]].l != -1) ans -= ct[ct[LIndex[i]].l].ans; if(k <= ans) { for(i = 0,tr = 0; i < RTop; ++i) if(ct[RIndex[i]].l != -1) RIndex[tr++] = ct[RIndex[i]].l; for(i = 0,tl = 0; i < LTop; ++i) if(ct[LIndex[i]].l != -1) LIndex[tl++] = ct[LIndex[i]].l; return GiveMetheAnwser(tl,tr,ct[Lroot].l,ct[Rroot].l,k,L,mid); } for(i = 0,tr = 0; i < RTop; ++i) if(ct[RIndex[i]].r != -1) RIndex[tr++] = ct[RIndex[i]].r; for(i = 0,tl = 0; i < LTop; ++i) if(ct[LIndex[i]].r != -1) LIndex[tl++] = ct[LIndex[i]].r; return GiveMetheAnwser(tl,tr,ct[Lroot].r,ct[Rroot].r,k-ans,mid+1,R);}int QueryKthEleOnCTandCTInBIT(int L,int R,int k,int n){ int LTop = 0,RTop = 0,tmp; tmp = L; while(tmp) { if(ctRootofBIT[tmp] != -1) LIndex[LTop++] = ctRootofBIT[tmp]; tmp -= lowbit(tmp); } tmp = R; while(tmp) { if(ctRootofBIT[tmp] != -1) RIndex[RTop++] = ctRootofBIT[tmp]; tmp -= lowbit(tmp); } return GiveMetheAnwser(LTop,RTop,ctRoot[L],ctRoot[R],k,1,siz);}struct OP{ int l,r,k;}op[MAXQ];int main(){ int i,j,n,m; int T; scanf("%d",&T); char ty[2]; while(T--) { scanf("%d %d",&n,&m); for(i = 1; i <= n; ++i) scanf("%d",&num[i]); memcpy(uni,num,sizeof(num)); for(i = 1,j = 0; i <= m; ++i) { scanf("%s",ty); if(ty[0] == 'Q') scanf("%d %d %d",&op[i].l,&op[i].r,&op[i].k); else scanf("%d %d",&op[i].l,&op[i].r),op[i].k = -1,uni[n+(++j)] = op[i].r; } siz = DelSame(uni,n+j); InitChairTree(n,siz); InitChairTreeInBIT(n); for(i = 1; i <= m; ++i) { if(op[i].k == -1) UpdateChairTreeInBIT(op[i].l,op[i].r,n); else printf("%d\n",QueryKthEleOnCTandCTInBIT(op[i].l-1,op[i].r,op[i].k,n)); } } return 0;}
- ZOJ 2112 Dynamic Rankings BIT套ChairTree
- ZOJ 2112 Dynamic Rankings 线段树套平衡树
- ZOJ 2112 Dynamic Rankings(Treap套在线段树上...)
- 【线段树套平衡树】 ZOJ 2112 Dynamic Rankings
- zoj 2112Dynamic Rankings(树状数组套splay)
- ZOJ 2112 Dynamic Rankings(树状数组套主席树)
- ZOJ 2112 Dynamic Rankings [树状数组套主席树]
- ZOJ 2112 Dynamic Rankings 线段树套平衡树
- Zoj 2112 Dynamic Rankings
- ZOJ 2112 Dynamic Rankings
- ZOJ 2112 Dynamic Rankings
- ZOJ 2112 Dynamic Rankings
- ZOJ 2112 Dynamic Rankings
- [ZOJ 2112]Dynamic Rankings
- zoj 2112 Dynamic Rankings
- 【ZOJ 2112】Dynamic Rankings
- ZOJ 2112 Dynamic Rankings
- ZOJ 2112 Dynamic Rankings
- 百度地图的两个问题以及解决方案
- 顺序栈的基本操作
- OC语法--KVC概念及用法
- C语言缓冲区&内存分配的理解
- hdu 4044 GeoDefense
- ZOJ 2112 Dynamic Rankings BIT套ChairTree
- C#扩充类
- Hibernate 参数设置一览表
- 链栈的基本操作
- Jquery 跨域访问
- iGrimace iOS应用闪退或图标消失的解决办法
- Web 移动开发规范概述
- 页面使用$.getJSON只获取一次数据,导致多个请求返回的都是第一个结果
- 2015年第七周图形用户界面(GUI)应用开发