[模板] 帶修改主席樹

我就算去學總體二分,CDQ分治,也不學樹套樹。樹套樹真好用node

帶修改主席樹

我相信來看帶修改主席樹的應該自認爲對主席樹非常瞭解,若是還沒深入理解請不要看繼續看下去了,由於那樣就算學了也沒法深入理解。
首先咱們來分析一下主席樹,它是權值線段樹+離散化+再加動態開點,使空間複雜度和時間複雜度都降到了\(nlogn\)。那麼若是帶一個單點修改該怎麼辦?咱們就想到了支持單點修改,區間查詢的數據結構樹狀數組和線段樹,但因爲線段樹常數又大,碼量又大於樹狀數組。因此在這裏咱們用樹狀數組套主席樹。咱們先來看一下樹狀數組的圖。
ios

這時容易發現,只要把樹狀數組上的每個節點換成一顆主席樹就好了,
單點修改,直接按照樹狀數組的修改就好了。
若是不理解的話,就想象一下樹狀數組的每個節點掛了一顆主席樹。數組

時間複雜度

主席樹查詢複雜度爲\(nlogn\),樹狀數組時間複雜度爲\(logn\),因此時間複雜度爲\(n{logn}^2\)數據結構

空間複雜度

主席樹空間複雜度爲\(nlogn\),每一個節點最多存入\(logn\)個樹狀數組(由於每次加lowbit(i)),
因爲咱們是在線開點,因此空間複雜度爲\(n{logn}^2\)
代碼以下:spa

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[100010],hash[101000],tot,root[201000],cnt,n,m,tt,qll[200100],qrr[20000];
int q1,q2,id[201000],b[201000];
struct TREE
{
    int ln,rn,zhi;
}t[10010000];
struct NODE
{
    int l,r,k,flag;
}q[100100];
int lowbit(int x) {return (x)&(-x);}
void gai(int &node,int l,int r,int hs,int v)
{
    if(!node) node=++tot;
    t[node].zhi+=v;
    if(l==r) return;
    int mid=(l+r)/2;
    if(hs<=mid) gai(t[node].ln,l,mid,hs,v);
    else gai(t[node].rn,mid+1,r,hs,v);
}
void add(int p,int v)
{
    hash[p]=lower_bound(a+1,a+1+tt,hash[p])-a;
    //cout<<hash[p]<<endl;
    for(int i=p;i<=n;i+=lowbit(i)) gai(root[i],1,tt,hash[p],v);
}
char s[2];
int SUM()
{
    int ans1=0,ans2=0;
    for(int i=1;i<=q1;i++) ans1+=t[t[qrr[i]].ln].zhi;
    for(int i=1;i<=q2;i++) ans2+=t[t[qll[i]].ln].zhi;
    return ans1-ans2;

}
int cha(int qr,int ql,int l,int r,int k)
{
    q1=0,q2=0;
    for(int i=qr;i>=1;i-=lowbit(i)) qrr[++q1]=root[i];
    for(int i=ql;i>=1;i-=lowbit(i)) qll[++q2]=root[i];
    while(l<r)
    {
        int lsiz=SUM(),mid=(l+r)/2;
        if(k<=lsiz) 
        {
            for(int i=1;i<=q1;i++) qrr[i]=t[qrr[i]].ln;
            for(int i=1;i<=q2;i++) qll[i]=t[qll[i]].ln;
            r=mid;
        }
        else
        {
            for(int i=1;i<=q1;i++) qrr[i]=t[qrr[i]].rn;
            for(int i=1;i<=q2;i++) qll[i]=t[qll[i]].rn;
            l=mid+1;k-=lsiz;
        }
    }
    return l;
}
int main()
{
    int x,y,z;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);b[i]=a[i];
        hash[++cnt]=a[i];
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%s",s);
        if(s[0]=='Q')
        scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k),q[i].flag=1;
        else
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            a[++cnt]=q[i].r;hash[cnt]=a[cnt];
        }
    }
    sort(a+1,a+1+cnt);
    tt=unique(a+1,a+1+cnt)-a-1;
    for(int i=1;i<=n;i++)
    add(i,1);
    for(int i=1;i<=m;i++)
    {
        if(q[i].flag==1)
        printf("%d\n",a[cha(q[i].r,q[i].l-1,1,tt,q[i].k)]);
        else
        {
            hash[q[i].l]=b[q[i].l];
            add(q[i].l,-1);
            hash[q[i].l]=q[i].r;
            b[q[i].l]=q[i].r;
            add(q[i].l,1);
        }
    }
}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息