Luogu P2617 Dynamic Rankings

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);
        }

    }
}

樹狀數組其實很有用,也不是很難(的樣子。。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章