ZOJ 2112 Dynamic Rankings BIT套ChairTree

劳资就是想单纯的测个模板,怎么就特喵的这么难。

首先说一下自己对主席树的理解。

作用:确定区间[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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值