• 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);
            }
        }
    }
    
  • 相关阅读:
    java rmi 入门实例
    flex“深拷贝”
    Cygwin 下部署Hadoop
    Hadoop学习原地
    Scribe+HDFS日志收集系统安装方法
    使用HDFS来进行线上应用的文件存储
    转:C++初始化成员列表
    转:为什么数据库选B-tree或B+tree而不是二叉树作为索引结构
    B树、B+树、B*树三者的对比详解
    转载:构造函数不能声明为虚函数,而构造函数可以。为什么?
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10308857.html
Copyright © 2020-2023  润新知