Dynamic Rankings,洛谷P2617,树状数组+主席树

正题

      这道题我理解了半天,网上好的题解我没有看懂,所以在这里尽量写得详细简略一些。

      动态第k大要了解的是两个东西。

      一个是树状数组的概念,一个是主席树(动态开点线段树)。

     先讲树状数组;

     1.定义一个点i维护的信息是[i-lowbit(i)+1,i].lowbit()这个函数的意义是i在二进制下末尾零和倒数第一个数组成的数。像lowbit(7) = lowbit( (111)2 ) = (1)2 = 1 。2指的是二进制下。

     2.那么如何扯到这个题上面去呢?

     再讲主席树。

     1.在求静态第k大的过程中,我们习惯于用前缀和主席树来处理区间问题,然后利用“每次只加一条链”的性质节省空间。

     2.但是在此题中,如果还是用根来表示位置,用底层主席树维护的值来表示权值的话,那么修改必将很麻烦。

     3.因为在这时,更改当前点x的值是会影响到x~n的主席树的构成。

      所以我们在这里提出——用树状数组套一套

      我们现在建出来的主席树,第i个根维护的是[i-lowbit(i)+1,i]区间的信息,而不是像以前的前缀树一样。但是很多人想问,前缀树有自己优化空间的方法,树状数组套主席树有自己的优化方法吗?

      没有

      所以我们要暴力开空间

void update(int &now,int l,int r){//这里的now是引用,表示上一层的左儿子或右儿子
    if(now==0) now=++tot;//我还没有这个儿子,新建出来
    c[now]+=d;//加上一个d,d在增加的时候为1,减的时候为0
    if(l==r) return ;
    if(v<=(l+r)/2) update(ls[now],l,(l+r)/2);//在左边,往左边找
    else update(rs[now],(l+r)/2+1,r);//在右边,往右边找
}

       代码理解好了,什么都没有事。

      最后要看的还是全部。

#include
#include
#include
#include
using namespace std;

int a[10010];
int n,m;
int root[10010],ls[2600010],rs[2600010],c[2600010];
int tot=0;
int xx[30],yy[30];
int v,d;

int lowbit(int x){
    return x&-x;
}

void update(int &now,int l,int r){
    if(now==0) now=++tot;
    c[now]+=d;
    if(l==r) return ;
    if(v<=(l+r)/2) update(ls[now],l,(l+r)/2);
    else update(rs[now],(l+r)/2+1,r);
}

void change(){
    int x,b;
    scanf("%d %d",&x,&b);
    d=-1;v=a[x];
    for(int i=x;i<=n;i+=lowbit(i))//把原来的删掉
        update(root[i],0,1e9);
    d=1;v=b;
    for(int i=x;i<=n;i+=lowbit(i))//把新的加上
        update(root[i],0,1e9);
    a[x]=b;
}

int query(){
    int x,y,k;
    scanf("%d %d %d",&x,&y,&k);
    x--;
    swap(x,y);
    int t1=0,t2=0;
    for(int i=x;i>=1;i-=lowbit(i)) xx[++t1]=root[i];//记住,这里是log个根一起跑
    for(int i=y;i>=1;i-=lowbit(i)) yy[++t2]=root[i];
    int l=0,r=1e9;//二分模拟边界变化
    while(l


你可能感兴趣的:(Dynamic Rankings,洛谷P2617,树状数组+主席树)