zoukankan      html  css  js  c++  java
  • 主席树套树状数组——带修区间第k大zoj2112

    主席树带修第k大 
    https://www.cnblogs.com/Empress/p/4659824.html 讲的非常好的博客

    首先按静态第k大建立起一组权值线段树(主席树) 然后现在要将第i个值从a改为b, 由主席树前缀和的性质可知修改第i个值会对T[i]...T[n]棵权值线段树造成相同的影响 如果暴力进行维护必定超时 那么如何优化这种修改? 我们知道动态维护前缀和可以用bit在log时间内完成 那么对于动态维护具有前缀和性质的主席树,我们也可以套上bit来完成 update:将第i个值从a改成b 根据bit的原理,第i个元素的修改会影响第i+lowbit(i)个元素 那么现在第i棵树修改了,第i+lowbit(i)棵树也应该影响 即第i棵树的位置a -1,同样的第i+lowbit(i)棵树的位置a -1 同理这批树的位置b +1即可 query:询问区间[l,r]第k大元素 即求T[r]-T[l]的前缀和即可 查询时要把bit对应的修改套上

    一些实现上的细节

      按照静态主席树建立 T[1-n]
      用相同结构的树状数组 S[1-n]来维护 T[1-n]
      S[i]表示一棵权值线段树的根节点

      update:修改位置i,必然要修改S[i],那么S[i+lowbit i]也要修改
      query [l,r]:转化成前缀和问题,静态的初始主席树 T[r]-T[l-1], 再加上树状数组中修改的量 S[r]-S[l-1],

    由于需要到子树里更新或查询,开一个数组use[i]表示第i棵树状数组当前在哪个子树更新或查询

    我写的不知道为什么在zoj会段错误。。

    在洛谷上就能过。。

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 600005
    inline int low(int x){return x&(-x);}
    struct Q{char op[2];int l,r,k;}op[maxn];
    int n,a[maxn],m,tot,b[maxn],q;
    
    struct Node{int lc,rc,sum;}T[maxn*50];
    int rt[maxn],S[maxn],use[maxn],size;
    int build(int l,int r){
        int now=++size;
        if(l==r)return now;
        int mid=l+r>>1;
        T[now].lc=build(l,mid);
        T[now].rc=build(mid+1,r);
        return now;
    }
    int update(int last,int pos,int v,int l,int r){
        int now=++size;
        T[now]=T[last];T[now].sum+=v;
        if(l==r)return now;
        int mid=l+r>>1;
        if(pos<=mid)T[now].lc=update(T[last].lc,pos,v,l,mid);
        else T[now].rc=update(T[last].rc,pos,v,mid+1,r);
        return now;
    }
    int Sum(int x){//查询前x棵树的修改值 
        int res=0;
        while(x){
            res+=T[T[use[x]].lc].sum;
            x-=low(x);
        } 
        return res;
    }
    void Update(int x,int pos,int v){
        while(x<=n){
            S[x]=update(S[x],pos,v,1,m);
            x+=low(x);
        }
    }
    int query(int L,int R,int st,int ed,int l,int r,int k){
        if(l==r)return l;
        int mid=l+r>>1;
        int sum=Sum(R)-Sum(L)+T[T[ed].lc].sum-T[T[st].lc].sum;
        if(k<=sum){
            for(int i=L;i;i-=low(i))
                use[i]=T[use[i]].lc;
            for(int i=R;i;i-=low(i))
                use[i]=T[use[i]].lc;
            return query(L, R, T[st].lc, T[ed].lc,l,mid,k);
        }
        else {
            for(int i=L;i;i-=low(i))
                use[i]=T[use[i]].rc;
            for(int i=R;i;i-=low(i))
                use[i]=T[use[i]].rc;
            return query(L, R, T[st].rc, T[ed].rc,mid+1,r, k-sum);
        }
    }
    void init(){
        m=tot=size=0;memset(rt,0,sizeof rt);
        memset(S,0,sizeof S);
    }
    int main(){
    
    {
            init();
            scanf("%d%d",&n,&q);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[++tot]=a[i];
            for(int i=1;i<=q;i++){
                scanf("%s",op[i].op);
                if(op[i].op[0]=='Q')scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);
                else {
                    scanf("%d%d",&op[i].l,&op[i].r);
                    b[++tot]=op[i].r;
                }
            }
            sort(b+1,b+1+tot);//离散化 
            m=unique(b+1,b+1+tot)-(b+1);
    
            rt[0]=build(1,m);
            for(int i=1;i<=n;i++){//建立静态主席树 
                int pos=lower_bound(b+1,b+1+m,a[i])-b;
                rt[i]=update(rt[i-1],pos,1,1,m);
                S[i]=rt[0]; 
            }
            for(int i=1;i<=q;i++){
                int l=op[i].l,r=op[i].r,k=op[i].k;
                if(op[i].op[0]=='Q'){//查询,准备好要用到的线段树 
                    for(int j=l-1;j;j-=low(j))use[j]=S[j];
                    for(int j=r;j;j-=low(j))use[j]=S[j];
                    cout<<b[query(l-1,r,rt[l-1],rt[r],1,m,k)]<<'
    ';
                }
                else {
                    int pos1=lower_bound(b+1,b+1+m,a[l])-b;
                    int pos2=lower_bound(b+1,b+1+m,r)-b;
                    Update(l,pos1,-1);Update(l,pos2,1);
                    a[l]=r;
                }
            }
        }    
    } 

    下面是一份模板。。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define lson l, m
    #define rson m+1, r
    const int N=60005;
    int a[N], Hash[N];
    int T[N], L[N<<5], R[N<<5], sum[N<<5];
    int S[N];
    int n, m, tot;
    struct node
    {
        int l, r, k;
        bool Q;
    }op[10005];
    
    int build(int l, int r)
    {
        int rt=(++tot);
        sum[rt]=0;
        if(l!=r)
        {
            int m=(l+r)>>1;
            L[rt]=build(lson);
            R[rt]=build(rson);
        }
        return rt;
    }
    
    int update(int pre, int l, int r, int x, int val)
    {
        int rt=(++tot);
        L[rt]=L[pre], R[rt]=R[pre], sum[rt]=sum[pre]+val;
        if(l<r)
        {
            int m=(l+r)>>1;
            if(x<=m)
                L[rt]=update(L[pre], lson, x, val);
            else
                R[rt]=update(R[pre], rson, x, val);
        }
        return rt;
    }
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    int use[N];
    void add(int x, int pos, int val)
    {
        while(x<=n)
        {
            S[x]=update(S[x], 1, m, pos, val);
            x+=lowbit(x);
        }
    }
    
    int Sum(int x)
    {
        int ret=0;
        while(x>0)
        {
            ret+=sum[L[use[x]]];
            x-=lowbit(x);
        }
        return ret;
    }
    
    int query(int u, int v, int lr, int rr, int l, int r, int k)
    {
        if(l>=r)
            return l;
        int m=(l+r)>>1;
        int tmp=Sum(v)-Sum(u)+sum[L[rr]]-sum[L[lr]];
        if(tmp>=k)
        {
            for(int i=u;i;i-=lowbit(i))
                use[i]=L[use[i]];
            for(int i=v;i;i-=lowbit(i))
                use[i]=L[use[i]];
            return query(u, v, L[lr], L[rr], lson, k);
        }
        else
        {
            for(int i=u;i;i-=lowbit(i))
                use[i]=R[use[i]];
            for(int i=v;i;i-=lowbit(i))
                use[i]=R[use[i]];
            return query(u, v, R[lr], R[rr], rson, k-tmp);
        }
    }
    
    void modify(int x, int p, int d)
    {
        while(x<=n)
        {
            S[x]=update(S[x], 1, m, p, d);
            x+=lowbit(x);
        }
    }
    
    int main()
    {
        int t;
        scanf("%d", &t);
        while(t--)
        {
            int q;
            scanf("%d%d", &n, &q);
            tot=0;
            m=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d", &a[i]);
                Hash[++m]=a[i];
            }
            for(int i=0;i<q;i++)
            {
                char s[10];
                scanf("%s", s);
                if(s[0]=='Q')
                {
                    scanf("%d%d%d", &op[i].l, &op[i].r, &op[i].k);
                    op[i].Q=1;
                }
                else
                {
                    scanf("%d%d", &op[i].l, &op[i].r);
                    op[i].Q=0;
                    Hash[++m]=op[i].r;
                }
            }
            sort(Hash+1, Hash+1+m);
            int mm=unique(Hash+1, Hash+1+m)-Hash-1;
            m=mm;
            T[0]=build(1, m);
            for(int i=1;i<=n;i++)
                T[i]=update(T[i-1], 1, m, lower_bound(Hash+1, Hash+1+m, a[i])-Hash, 1);
            for(int i=1;i<=n;i++)
                S[i]=T[0];
            for(int i=0;i<q;i++)
            {
                if(op[i].Q)
                {
                    for(int j=op[i].l-1;j;j-=lowbit(j))
                        use[j]=S[j];
                    for(int j=op[i].r;j;j-=lowbit(j))
                        use[j]=S[j];
                    printf("%d
    ", Hash[query(op[i].l-1, op[i].r, T[op[i].l-1], T[op[i].r], 1, m, op[i].k)]);
                }
                else
                {
                    modify(op[i].l, lower_bound(Hash+1, Hash+1+m, a[op[i].l])-Hash, -1);
                    modify(op[i].l, lower_bound(Hash+1, Hash+1+m, op[i].r)-Hash, 1);
                    a[op[i].l]=op[i].r;
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    hdu 3268 09 宁波 现场 I
    hdu 3697 10 福州 现场 H
    CodeForces Round #521 (Div.3) D. Cutting Out
    #Leetcode# 226. Invert Binary Tree
    zufe 蓝桥选拔
    #Leetcode# 100. Same Tree
    #Leetcode# 6. ZigZag Conversion
    PAT 1084 外观数列
    #Leetcode# 38. Count and Say
    #Leetcode# 22. Generate Parentheses
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10765363.html
Copyright © 2011-2022 走看看