标签:
劳资就是想单纯的测个模板,怎么就特喵的这么难。
首先说一下自己对主席树的理解。
作用:确定区间[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 0x3f3f3f using 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
标签:
原文地址:http://blog.csdn.net/zmx354/article/details/45168883