• BZOJ1901 Dynamic Rankings|带修主席树


    题目链接:戳我

    其实我并不会做,于是看了题解

    我们都知道主席树是利用前缀和记录历史版本来搞区间K大的一种数据结构。不过一般的主席树只能搞定静态区间第K大。如果带修怎么办呢?

    想一下。。。单点修改+区间查询,我们是否能想到树状数组呢?

    那么思路就出来了。用树状数组来维护主席树的前缀和!!这里的主席树只需要维护对于每个节点所包含的值域区间中数的个数即可,不需要继承历史版本。

    单次操作复杂度两个log,应该是稳稳的了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define MAXN 100010
    using namespace std;
    inline int read()
    {
        int f=1,x=0; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48); ch=getchar();}
        return x*f;
    }
    int n,m,q_cnt,cnt,tot,cnt1,cnt2;
    int a[MAXN],S[MAXN],rt[MAXN],tmp1[MAXN],tmp2[MAXN];
    struct Node{int l,r,k,pos,t;}q[MAXN];
    struct Node2{int ls,rs,v;}t[MAXN<<5];
    inline void modify(int &now,int l,int r,int pos,int k)
    {
        if(!now) now=++tot;
        t[now].v+=k;
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) modify(t[now].ls,l,mid,pos,k);
        else modify(t[now].rs,mid+1,r,pos,k);
    }
    inline void pre_modify(int x,int k)
    {
        int pos=lower_bound(&S[1],&S[1+cnt],a[x])-S;
        for(int i=x;i<=n;i+=i&(-i))
            modify(rt[i],1,cnt,pos,k);
    }
    inline int query(int l,int r,int k)
    {
        if(l==r) {return S[l];}
        int cur_ans=0;
        for(int i=1;i<=cnt1;i++) cur_ans+=t[t[tmp1[i]].ls].v;
        for(int i=1;i<=cnt2;i++) cur_ans-=t[t[tmp2[i]].ls].v;
        int mid=(l+r)>>1;
        if(cur_ans>=k)
        {
            for(int i=1;i<=cnt1;i++) tmp1[i]=t[tmp1[i]].ls;
            for(int i=1;i<=cnt2;i++) tmp2[i]=t[tmp2[i]].ls;
            return query(l,mid,k);
        }
        else 
        {
            for(int i=1;i<=cnt1;i++) tmp1[i]=t[tmp1[i]].rs;
            for(int i=1;i<=cnt2;i++) tmp2[i]=t[tmp2[i]].rs;
            return query(mid+1,r,k-cur_ans);
        }
    }
    inline void pre_query(int l,int r,int k)
    {
        cnt1=cnt2=0;
        for(int i=r;i;i-=i&(-i)) tmp1[++cnt1]=rt[i];
        for(int i=l;i;i-=i&(-i)) tmp2[++cnt2]=rt[i];
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) a[i]=read(),S[++cnt]=a[i];
        for(int i=1;i<=m;i++)
        {
            char cur[10];
            scanf("%s",cur);
            if(cur[0]=='Q') q[i]=(Node){read()-1,read(),read(),0,0};
            else q[i]=(Node){0,0,0,read(),read()},S[++cnt]=q[i].t;
        }
        sort(&S[1],&S[cnt+1]);
        cnt=unique(&S[1],&S[cnt+1])-S-1;
        for(int i=1;i<=n;i++) pre_modify(i,1);
        for(int i=1;i<=m;i++)
        {
            if(q[i].k!=0)
            {
                pre_query(q[i].l,q[i].r,q[i].k);
                printf("%d
    ",query(1,cnt,q[i].k));
            }
            else
            {
                pre_modify(q[i].pos,-1);
                a[q[i].pos]=q[i].t;
                pre_modify(q[i].pos,1);
            }
        }
    }
    
  • 相关阅读:
    [题解] LuoguP6185 [NOI Online 提高组]冒泡排序
    [题解] LuoguP5339 [TJOI2019]唱、跳、rap和篮球
    [题解] LuoguP4168 [Violet]蒲公英
    [题解] LuoguP4705玩游戏
    [题解 LuoguP4491 [HAOI2018]染色
    [题解] LuoguP3768 简单的数学题
    杜教筛
    莫比乌斯反演学习笔记
    [题解] LuoguP2257 YY的GCD
    [题解] LuoguP2764 最小路径覆盖问题
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10308857.html
Copyright © 2020-2023  润新知