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;}


0 0
原创粉丝点击