BZOJ 3524 [Poi2014]Couriers 可持久化线段树

题意:链接

方法:可持久化线段树。

解析:

可持久化数据结构好神啊,感觉都好玄妙的感觉。

首先建树的目的就是建立一棵权值树,维护的是在L,R里某些权值的数的出现个数。然后呢,对于1~n每个节点建一棵树,并且是基于前一棵树的基础上的。然后对于每一次的新值我们只需要update一次,并且连接一下原来的树?

神犇们不是说这种结构就是一堆线段树连啊连就出来了吗。

查询的时候呢?有一些小改变,据说是以二分为基础的查询。

神犇们发明这种数据结构的时候,就发现了这种数据结构里的所有线段树是可以相减的这种性质,于是,我们就可以二分答案在左边还是右边,递归搞下去最终的l就是目标值。

感觉要真正的理解还需要时间?我认为我现在就是理解个大概吧。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 500010
using namespace std;
struct node
{
    int lson,rson,sum;
}seg[N*20];
int size;
int root[N];
void update(int p,int &q,int l,int r,int v)
{
    seg[++size]=seg[p],q=size;
    seg[q].sum++;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(v<=mid)update(seg[p].lson,seg[q].lson,l,mid,v);
    else update(seg[p].rson,seg[q].rson,mid+1,r,v);
}
int que(int L,int R,int l,int r,int k)
{
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(seg[seg[R].lson].sum-seg[seg[L].lson].sum>k)
    {
        return que(seg[L].lson,seg[R].lson,l,mid,k);
    }
    if(seg[seg[R].rson].sum-seg[seg[L].rson].sum>k)
    {
        return que(seg[L].rson,seg[R].rson,mid+1,r,k);
    }
    return 0;
}
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        update(root[i-1],root[i],1,n,x);
    }
    for(int i=1;i<=m;i++)
    {
        int L,R;
        scanf("%d%d",&L,&R);
        printf("%d\n",que(root[L-1],root[R],1,n,(R-L+1)>>1));
    }
}

你可能感兴趣的:(基础,方法,解析,update,结构)