首页 > 编程语言 > 详细

BZOJ1901:树套树之树状数组套主席树实现带修区间第K极值询问

时间:2018-07-26 17:42:54      阅读:153      评论:0      收藏:0      [点我收藏+]

这就是所谓的支持修改的主席树,其实我不太认为这是一个树套树,外面的那层树不够显然

int n,m,top,tot,sz;
int v[10005],num[20005],A[10005],B[10005],K[10005],flag[10005],hash[20005],root[10005];
int sum[2200005],lch[2200005],rch[2200005];
int L[35],R[35],a,b;

这个题大概能看出来离线操作的一些端倪来

top是个游标来指示num数组的,num把题目中涉及到的值都存起来了,然后再用hash离散化处理

这里的离散化是因为主席树是一个完全二叉树,是对权值的建树,如果不把1,2,4,6,7变成1,2,3,4,5势必要浪费大量的空间

A,B,K和flag把所有的查询工作存起来了,这也是主席树的特性之一,如果是那种强制在线的题,只能常规树套树了

root是用来存每一个树状数组节点(C数组)所引出的主席树的根节点,sum,lch和rch应该是线段树家族的常客了

这里补充一下主席树的基本知识,首先对要进行操作的序列的前缀建权值树。每当询问[l, r]的时候,只要用[1, r]的树减去[1, l-1]的树,然后就可以查找第K小了
然后对每个前缀建树的时候,只需要新增Logn个点,连到前一个前缀所对应的线段树上,这样就仿佛建了n棵线段树一样
查询操作的话,我们只要找到对应这个区间的线段树,然后再去按照正常的主席树查询就可以了

其实查询操作就是正规的主席树查询而已,只不过我们把初始节点也执行了更新操作,这样原树为空,所有的东西就都依托于树状数组了

这里可以联想一下二维树状数组那里的,我可以维护原始数据的前缀和,只用树状数组维护delta,也可以索性全部update

如果是索性全部update的话,查询的时候就要先查树状数组找到若干树状数组节点,再查询这些节点对应的主席树了

int query(int l,int r,int k)
{
    if(l==r) return l;
    int i,suml=0,sumr=0;
    for(i=1;i<=a;i++) suml+=sum[lch[L[i]]];
    for(i=1;i<=b;i++) sumr+=sum[lch[R[i]]];
    int mid=(l+r)>>1;
    if(sumr-suml>=k)
    {
        for(i=1;i<=a;i++) L[i]=lch[L[i]];
        for(i=1;i<=b;i++) R[i]=lch[R[i]];
        return query(l,mid,k);
    }
    else
    {
        for(i=1;i<=a;i++) L[i]=rch[L[i]];
        for(i=1;i<=b;i++) R[i]=rch[R[i]];
        return query(mid+1,r,k-(sumr-suml));
    }
}

最后查的结果是经过了离散化的,别忘了还原

更新操作就必须完全依赖树状数组了,更新都是先删再加,不管是删还是加,其根本的原理都是执行了一次insert,这样就会在原来的基础上多出logn个节点

这里我们就想到题目为啥要把所有的东西放在一起了,就是为了一块儿建树,更新的东西在查之前已经准备好了

再说说可持久化,可持久化是支持查询历史版本的,因为我的原始数据和更新数据都是一起建的,那么我更新之前和更新之后的东西,只要找到对应历史版本的树根查询就可以了

然后看一下更新操作:

void update(int last,int l,int r,int &rt,int w,int x)
{
    rt=++sz;
    sum[rt]=sum[last]+x;lch[rt]=lch[last];rch[rt]=rch[last];
    if(l==r) return;
    int mid=(l+r)>>1;
    if(w<=mid) update(lch[last],l,mid,lch[rt],w,x);
    else update(rch[last],mid+1,r,rch[rt],w,x);
}

纯粹的主席树update,只不过需要调用logn次,毕竟有logn个树状数组点嘛

如果我们把历史版本的root覆盖了,当然就是真的覆盖了,就像本题一样,因为题目也没问历史版本怎么怎么样了

总的来说,主席树这个东西,值得去细细研究一番

而且通过这个题,离散化的板子有啦,哈哈

 

BZOJ1901:树套树之树状数组套主席树实现带修区间第K极值询问

原文:https://www.cnblogs.com/aininot260/p/9372788.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!