Luogu P2617 Dynamic Rankings

3 篇文章 0 订阅
2 篇文章 0 订阅
Luogu P2617 Dynamic Rankings

主席树真的比树链剖分友善很多TuT

解法:主席树+树状数组

弄一个树状数组
这里写图片描述
这个样子
每一个格子(C开头那些)维护一棵主席树中的线段树(大概是这个意思吧!)
修改时要注意!!

如果把树状数组比作老板和员工,
那么 x+lowbit(x) 表示的就是比 x 高一级的他的上司,
x-lowbit(x) 表示的就是编号在 x 前的第一个不是 x 的下属的人。

学习树状数组处,非常清楚!

#include<cstdio>
#include<cstring>

int a[2000100],b[2000100],root[2000100];
int len=0,n,m,note=0;
struct nod1{int l,r,c,lc,rc;}tr[40001000];
//空间要开够! 

int lowbit(int x)
{
    return x & -x;
}//玄学lowbit 

void update(int &rt,int l,int r,int x)
{
    if(rt==0)
    {
        len++;rt=len;
        //少什么才建什么
    }
    tr[rt].c+=note;
    //note是1时是添加
    //note是-1时是删除
    //以此区分 
    if(l==r)return ;
    int mid=(l+r)/2;
    if(x<=mid)update(tr[rt].lc,l,mid,x);
    else update(tr[rt].rc,mid+1,r,x); 
}

void change(int x,int k)
{
    note=-1;
    for(int i=x;i<=n;i+=lowbit(i))
        update(root[i],0,1e9,a[x]);
    //把所有有累计x的都-- 
    a[x]=k;
    note=1;
    for(int i=x;i<=n;i+=lowbit(i))
        update(root[i],0,1e9,k);
    //添加 
}

int find(int x,int y,int l,int r,int k)
{
    x-=1;
    int numx=0,numy=0;
    int familyy[10010],familyx[10010];
    //与y有关的所有格子,与x有关的所有格子
    //后称“家族 ” 
    for(int i=x;i>=1;i-=lowbit(i))
    {
        numx++;familyx[numx]=root[i];
    }
    //记录 
    for(int i=y;i>=1;i-=lowbit(i))
    {
        numy++;familyy[numy]=root[i];
    }
    while(l<r)
    //二分寻找Kth 
    {
        int g=0;
        int mid=(l+r)/2;
        for(int i=1;i<=numy;i++)
            g+=tr[tr[familyy[i]].lc].c;
            //把y家族的左儿子所掌管的数量全部加起来才是1~y的数量 
        for(int i=1;i<=numx;i++)
            g-=tr[tr[familyx[i]].lc].c;
            //同理,加起来才是1~(x-1)左儿子所掌管的数量
            //剪了才是x~y区间的 
        if(k<=g)
        {
            for(int i=1;i<=numx;i++)
                familyx[i]=tr[familyx[i]].lc;
                //把家族向左边移去 
            for(int i=1;i<=numy;i++)
                familyy[i]=tr[familyy[i]].lc;
            r=mid;
        }
        else
        {
            for(int i=1;i<=numx;i++)
                familyx[i]=tr[familyx[i]].rc;
                //向右移 
            for(int i=1;i<=numy;i++)
                familyy[i]=tr[familyy[i]].rc;
            l=mid+1;k-=g;
        }
    }
    return r;
}

int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        note=1;
        for(int j=i;j<=n;j+=lowbit(j))
            update(root[j],0,1e9,a[i]);  
            //像静态主席树插入那样
            //树状数组中所有有关系的格子都要++ 
    }
    for(int i=1;i<=m;i++)
    {
        char ss[10];
        int k,x,y;
        scanf("%s",ss+1);
        if(ss[1]=='Q')
        {
            scanf("%d %d %d",&x,&y,&k);
            printf("%d\n",find(x,y,0,1e9,k));
        }   
        else
        {
            scanf("%d %d",&x,&k);
            change(x,k);
        }

    }
}

树状数组其实很有用,也不是很难(的样子。。)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值