BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)

我实在是不想再打一遍树状数组套替罪羊树了。。。

然后在普通平衡树瞎逛的时候找到了以前看过vector题解

于是我想:为啥不把平衡树换成vector呢???

然后我又去学了一下ZKW线段树

就用ZKW线段树套vector水过啦!!!

每个ZKW线段树的节点保存一个vector

操作1在分出的vector上查询比它小的数有多少个然后相加再加1

操作2二分再上操作1

操作3修改需要修改的节点的vector

操作4在分出vector上查询前驱取最大

操作5与操作4同理

luogu主站5772ms上卡过,开O2的话2296ms,bzoj上8196ms,COGS上直接过

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<vector>
#define il inline
#define rg register
#define vd void
#define sta static
using std::vector;
typedef long long ll;
il int gi(){
    rg int x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=50001;
int lb[maxn],W[maxn],n,N=65536,m;
typedef const int& fast;
vector<int>d[65537<<1];
vector<int>::iterator it;
il vd Insert(fast x,fast y){d[x].insert(upper_bound(d[x].begin(),d[x].end(),y),y);}
il vd Erase(fast x,fast y){d[x].erase(lower_bound(d[x].begin(),d[x].end(),y));}
il int Rank(fast x,fast y){return lower_bound(d[x].begin(),d[x].end(),y)-d[x].begin();}
il int Kth(fast x,fast y){return d[x][y-1];}
il int Prev(fast x,fast y){
    it=lower_bound(d[x].begin(),d[x].end(),y);
    if(it==d[x].begin())return -2147483647;
    return *--it;
}
il int Next(fast x,fast y){
    it=upper_bound(d[x].begin(),d[x].end(),y);
    if(it==d[x].end())return 2147483647;
    return *it;
}
il vd UPD1(rg int x,fast y){for(x+=N;x;x>>=1)Insert(x,y);}
il vd UPD2(rg int x,fast y){for(x+=N;x;x>>=1)Erase(x,y);}
il int max(fast a,fast b){return a>b?a:b;}
il int min(fast a,fast b){return a<b?a:b;}
il int RNK(rg int l,rg int r,fast k){
    sta int ret;ret=1;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1){
        if(~l&1)ret+=Rank(l^1,k);
        if(r&1)ret+=Rank(r^1,k);
    }return ret;
}
il int PRE(rg int l,rg int r,fast k){
    sta int ret;ret=-2147483647;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1){
        if(~l&1)ret=max(ret,Prev(l^1,k));
        if(r&1)ret=max(ret,Prev(r^1,k));
    }return ret;
}
il int NXT(rg int l,rg int r,fast k){
    sta int ret;ret=2147483647;
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1){
        if(~l&1)ret=min(ret,Next(l^1,k));
        if(r&1)ret=min(ret,Next(r^1,k));
    }return ret;
}
int main(){
    n=gi(),m=gi();
    for(N=1;N<n;N<<=1)
    for(rg int i=1;i<=n;++i)lb[i]=i&-i;
    for(rg int i=1;i<=n;++i){
        W[i]=gi();
        UPD1(i,W[i]);
    }
    int opt,l,r,k;
    while(m--){
        opt=gi();
        if(opt==3)l=gi(),k=gi();
        else l=gi(),r=gi(),k=gi();
        if(opt==1)printf("%d\n",RNK(l,r,k));
        else if(opt==2){
            sta int ll,rr,mid;
            ll=0,rr=100000000;
            while(ll<rr){
                mid=((ll+rr)>>1)+1;
                if(RNK(l,r,mid)>k)rr=mid-1;
                else ll=mid;
            }printf("%d\n",ll);
        }else if(opt==3)UPD2(l,W[l]),UPD1(l,W[l]=k);
        else if(opt==4)printf("%d\n",PRE(l,r,k));
        else if(opt==5)printf("%d\n",NXT(l,r,k));
        else while(1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/xzz_233/p/bzoj3196.html

时间: 2024-08-27 20:53:21

BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)的相关文章

BZOJ3196 二逼平衡树 【线段树套平衡树】

题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 输入格式 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名 若

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

3196. 二逼平衡树【线段树套splay】

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作 第二行有n个数,表示有序序列 下面有m行,opt表示操作标号 若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间

BZOJ3196二逼平衡树【树套树】

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3776  Solved: 1483 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n

BZOJ3196 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数

[BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过128MB = = 嗯就是这样,代码长度= =我写了260行......Debug了n小时= = 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #in

bzoj3196 二逼平衡树 线段树套平衡树

题意:您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,且最小的数) 题解:树套树,外层是一棵线段树,每个节点下有一棵平衡树(平衡树记录ls,rs,因此记录根节点就可以遍历整棵树),先不考虑空间问题,ask(l,r)可以分成多个线段树区间,每个区间下有平衡树可以查询排名,1&3-5操

ZJOI 2017 树状数组(线段树套线段树)

题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r](l\neq1)\) 的时候,则是在查询 \([l-1,r-1]\) .那么在查询 \([1,r]\) 的时候,只需要询问 \(r\) 的前后缀异或是否相等:在查询 \([l,r](l\neq 1)\) 的时候,只需要询问 \(a[l-1],a[r]\) 是否相等. 考虑 \(O(n^2)\) 的

【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #define N 50010 #define INF 2147483647 using namespace std; using namespace __gnu_pb