zoukankan      html  css  js  c++  java
  • 洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)

    【模板】二逼平衡树(树套树)

    题目描述

    您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

    查询k在区间内的排名

    查询区间内排名为k的值

    修改某一位值上的数值

    查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)

    查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)

    注意上面两条要求和tyvj或者bzoj不一样,请注意

    输入输出格式

    输入格式:

    第一行两个数 n,m 表示长度为n的有序序列和m个操作

    第二行有n个数,表示有序序列

    下面有m行,opt表示操作标号

    若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名

    若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数

    若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k

    若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱

    若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

    输出格式:

    对于操作1,2,4,5各输出一行,表示查询结果

    说明

    时空限制:2s,1256M

    (n,m leq 5cdot {10}^4)

    保证有序序列所有值在任何时刻满足([0, {10} ^8])

    题目来源:bzoj3196 / Tyvj1730 二逼平衡树,在此鸣谢

    此数据为洛谷原创。(特别提醒:此数据不保证操作4、5一定存在,故请务必考虑不存在的情况)


    前几天写了个树状数组套平衡树,最后懒得调了

    花了很久写+调弄了树状数组套可持久化线段树

    发现有思想的是 在多个可持久化树上一起二分

    很烦人的是查排名时的一些存在性问题

    最关键的是权值线段树想离散开点还必须离线

    代码也不好看,以后还会写的


    Code

    #include <cstdio>
    #include <algorithm>
    #define sf num[i].second.first
    #define ss num[i].second.second
    using namespace std;
    const int N=300010;
    const int inf=2147483647;
    int sum[N*50],ls[N*50],rs[N*50],root[N],las[N],tot,n,m,is,n_,n0,dat[N<<1];
    pair <int,pair<int,int> > num[N<<1];
    struct node
    {
        int opt,l,r,k;
    }op[N];
    void change(int &now,int l,int r,int pos,int delta)
    {
        if(!now) now=++tot;
        sum[now]+=delta;
        if(l==r) return;
        int mid=l+r>>1;
        if(pos<=mid) change(ls[now],l,mid,pos,delta);
        else change(rs[now],mid+1,r,pos,delta);
    }
    int query(int now,int l,int r,int pos)//1-pos的值
    {
        if(l==r)
            return is=sum[now],0;
        if(!now||!pos) return sum[now];
        int mid=l+r>>1;
        if(pos<=mid) return query(ls[now],l,mid,pos);
        else return sum[ls[now]]+query(rs[now],mid+1,r,pos);
    }
    void add(int x,int pos,int delta)
    {
        while(x<=n_)
        {
            change(root[x],1,n,pos,delta);
            x+=x&-x;
        }
    }
    int Rank(int l,int r,int pos)//查询l-r区间pos的排名
    {
        if(!pos) return 0;
        int rk=0,cnt0=0;
        for(int i=l-1;i;i-=i&-i)
            is=0,rk-=query(root[i],1,n,pos),cnt0-=is;
        for(int i=r;i;i-=i&-i)
            is=0,rk+=query(root[i],1,n,pos),cnt0+=is;
        return rk+(cnt0>0);
    }
    int rl[N],rr[N];
    int frank(int l,int r,int k)//l到r排名为k的数
    {
        int ad,de;
        for(int i=l-1;i;i-=i&-i) rl[i]=root[i];
        for(int i=r;i;i-=i&-i) rr[i]=root[i];
        int L=1,R=n;
        while(L<R)
        {
            ad=de=0;
            int Mid=L+R>>1;
            for(int i=l-1;i;i-=i&-i) de+=sum[ls[rl[i]]];
            for(int i=r;i;i-=i&-i) ad+=sum[ls[rr[i]]];
            if(ad-de>=k)
            {
                R=Mid;
                for(int i=l-1;i;i-=i&-i) rl[i]=ls[rl[i]];
                for(int i=r;i;i-=i&-i) rr[i]=ls[rr[i]];
            }
            else
            {
                L=Mid+1;
                k-=ad-de;
                for(int i=l-1;i;i-=i&-i) rl[i]=rs[rl[i]];
                for(int i=r;i;i-=i&-i) rr[i]=rs[rr[i]];
            }
        }
        return dat[L];
    }
    void pre(int l,int r,int pos)
    {
        int rk=Rank(l,r,pos-1);
        if(!rk) printf("%d
    ",-inf);
        else printf("%d
    ",frank(l,r,rk));
    }
    void suc(int l,int r,int pos)
    {
        add(l,pos+1,1);
        int rk=Rank(l,r,pos+1);
        add(l,pos+1,-1);
        if(rk==r+2-l) printf("%d
    ",inf);
        else printf("%d
    ",frank(l,r,rk));
    }
    void init()
    {
        scanf("%d%d",&n_,&m);
        for(int i=1;i<=n_;i++)
        {
            scanf("%d",&num[i].first);
            num[i].second.first=i;
        }
        n0=n_;
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&op[i].opt);
            if(op[i].opt==3)
                scanf("%d%d",&op[i].l,&op[i].k);
            else
                scanf("%d%d%d",&op[i].l,&op[i].r,&op[i].k);
            if(op[i].opt!=2)
            {
                num[++n0].first=op[i].k;
                num[n0].second.first=i+n_;
            }
        }
        sort(num+1,num+1+n0);
        num[0].first=inf;
        for(int i=1;i<=n0;i++)
        {
            if(num[i].first!=num[i-1].first) ++n;
            ss=n,dat[n]=num[i].first;
        }
        for(int i=1;i<=n0;i++)
        {
            if(sf<=n_) las[sf]=ss,add(sf,ss,1);
            else op[sf-n_].k=ss;
        }
    }
    void work()
    {
        for(int i=1;i<=m;i++)
        {
            if(op[i].opt==1)
            {
                add(op[i].l,op[i].k,1);
                printf("%d
    ",Rank(op[i].l,op[i].r,op[i].k));
                add(op[i].l,op[i].k,-1);
            }
            else if(op[i].opt==2) printf("%d
    ",frank(op[i].l,op[i].r,op[i].k));
            else if(op[i].opt==3)
            {
                add(op[i].l,las[op[i].l],-1);
                las[op[i].l]=op[i].k;
                add(op[i].l,las[op[i].l],1);
            }
            else if(op[i].opt==4)
                pre(op[i].l,op[i].r,op[i].k);
            else
                suc(op[i].l,op[i].r,op[i].k);
        }
    }
    int main()
    {
        init();
        work();
        return 0;
    }
    
    

    2018.8.1

  • 相关阅读:
    使用Newtonsoft进行JSON序列化时将枚举序列化为字符串的方法
    通过javac导出Jar包
    JAVA中JDBC连接Mysql数据库简单测试
    使用Swashbuckle.AspNetCore生成.NetCore WEBAPI的接口文档
    CentOS7中使用yum安装Nginx的方法
    Dockerfile 指令 ADD 和 COPY介绍
    Azure Web应用中设置静态虚拟目录的方法(比如部署Django需要用到)
    pip常用命令(转载)
    android发布新版忘记keystore(jks)密码终极解决方案
    IntelliJ Idea 常用快捷键列表
  • 原文地址:https://www.cnblogs.com/butterflydew/p/9403390.html
Copyright © 2011-2022 走看看