首页 > 其他分享 >区间k小值(可持久化线段树)

区间k小值(可持久化线段树)

时间:2024-08-25 17:16:06浏览次数:10  
标签:typedef 持久 val int 线段 leq 小值 inline return

题目描述
给定一个序列\(a_1,a_2,\dots,a_n\),\(m\)次操作,每次给定\(l,r,k\),问\(a_l,a_{l+1},\dots,a_r\)中第\(k\)小的值。
输入
第一行一个正整数\(T(1\leq T\leq 3)\),表示测试数据的数量。

每组数据第一行\(n,m(1\leq n,m\leq 100000)\)。

第二行\(n\)个正整数\(a_1,a_2,\dots,a_n(1\leq a_i\leq n)\)。

接下来\(m\)行,每行描述一个操作,其中\(1\leq l\leq r\leq n,1\leq k\leq r-l+1\)。
输出
对于每个询问,输出一行一个整数,即第\(k\)小的值。
样例输入 Copy
1
5 5
1 3 5 4 2
1 3 3
2 4 2
1 5 2
4 4 1
3 5 1
样例输出 Copy
5
4
2
4
2

考虑二分答案ans在[l,r]上的<=ans的数和k的关系,用f[i][j]表示前i个数里j出现的次数,通过可持久化将j作为线段树的点

然后考虑线段树上二分去掉一个log

注意不能build,否则会超时,原因尚不明确

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
//如果在不支持 avx2 的平台上将 avx2 换成 avx 或 SSE 之一
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef vector<string> VS;
typedef vector<int> VI;
typedef vector<vector<int>> VVI;
vector<int> vx;
inline int mp(int x) {return upper_bound(vx.begin(),vx.end(),x)-vx.begin();}
inline int log_2(int x) {return 31-__builtin_clz(x);}
inline int popcount(int x) {return __builtin_popcount(x);}
inline int lowbit(int x) {return x&-x;}
const int N = 1e5+10,M = 2e6;
//T[i]里保存的是i号线段树的根节点标号,l,r,val要开到nlogn
int a[N],T[N],l[M],r[M],val[M];
int n,m,tot;
inline void pushup(int p)
{
    val[p] = val[l[p]] + val[r[p]];
}

//对根为x的线段树区间[a,b]里的c点修改d
//注意change里的左右节点编号
int change(int x,int a,int b,int c,int d)
{
    int y = ++tot;
    if(a==b)
    {
        val[y] = val[x] + d;
        return y;
    }
    int M = (a+b)/2;
    if(c<=M) 
    {
        l[y] = change(l[x],a,M,c,d);
        r[y] = r[x];
    }
    else
    {
        l[y] = l[x];
        r[y] = change(r[x],M+1,b,c,d); 
    }
    pushup(y);
    //if(a==4&&b==4) cout<<l[y]<<' '<<r[y]<<'\n';
    return y;
}
//对根为x当前区间为[a,b]的线段树查询区间[ql,qr]
int query(int x,int a,int b,int ql,int qr)
{
    if(ql==a&&b==qr) return val[x];
     
    int m = (a+b)/2;
    //注意此处的修改用ql,qr表示询问区间
    if(qr<=m) return query(l[x],a,m,ql,qr);
    else if(ql>m) return query(r[x],m+1,b,ql,qr);
    else return query(l[x],a,m,ql,m)+query(r[x],m+1,b,m+1,qr);
}
//check(x)计算的是[l,r]中小于等于x的数字个数
//注意调用query时使用的是T数组里的标号
inline int ask(int x,int y,int k)
{
    int a = 1,b = n;
    while(a < b)
    {
        int m = (a+b)/2;
        int t = val[l[y]] - val[l[x]];
        if(t >= k) x = l[x],y = l[y],b = m;
        else //注意若在右半边需要把k-=t
        k -= t, x = r[x], y = r[y], a = m+1;
    }
    return a;
}
void solve()
{
    tot = 0;
    cin>>n>>m;
    for(int i=1;i<=n;++i) cin>>a[i];
    
    // T[0] = 1;
    // build(1,n);
     
    for(int i=1;i<=n;++i) T[i] = change(T[i-1],1,n,a[i],1);
     
    while(m--)
    {
        int l,r,k;
        cin>>l>>r>>k;
        cout<<ask(T[l-1],T[r],k)<<'\n';
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        solve();
    }
}

标签:typedef,持久,val,int,线段,leq,小值,inline,return
From: https://www.cnblogs.com/ruoye123456/p/18379157

相关文章

  • 线段树(3)——区间操作叠加
    如果我既有区间乘法又有区间加法,我应该怎么办呢?这时候需要写两个标记。假设只写一个标记。标记加法:此时对于乘法操作,因为是将\(t_i+lazy_i\)乘以\(x\),这样子显然一个懒惰标记做不到。标记乘法:那我加法咋办?那两个标记怎么用呢?首先假设加法标记为\(lazy\),乘法标记为\(multi......
  • 线段树维护单调栈——区间查询版本 & 维护递减序列
    这次算是完全搞懂了吧()()(#include<bits/stdc++.h>#defineraedread#definecaclcalc#definepbpush_back#definepiipair<int,int>#defineintlonglong#definefifirst#definesesecond#definelsp<<1#definersp<<1|1usingn......
  • ZNS SSD是不是持久缓存的理想选择?
    随着数据量的增加和技术的进步,对于高效、可靠的存储解决方案的需求日益增长。传统的基于块的SSD虽然具有成本效益和持久性的优点,但在处理写密集型和更新密集型工作负载时存在局限性。NAND闪存的特点是数据只能按页(例如4KiB)写入,不支持原地更新,必须以块为单位进行擦除。然而,块接......
  • 线段树(2)——懒惰标记Lazy Tag(单运算)及例题
    上一篇文章我们讲了线段树的最基本的操作。如果有一种操作叫做区间加法呢?这个时候显然可以依次单点修改,但是时间复杂度太高了。所以可以考虑优化,由于思考过程可能很长,此处直接引入懒惰标记。懒惰标记就是在对一颗树的所有节点进行某种统一操作时,只对根节点做一个标记表示它的子树......
  • MySQL 持久化系统变量
    setpersist会将变量持久化到文件mysqld-auto.cnf文件中,该文件位于数据目录下。resetpersist会移除mysqld-auto.cnf文件中持久化的变量。 MySQL可以在运行时持久化全局系统变量。虽然许多系统变量可以在启动时通过my.cnf配置文件设置,或在运行时使用set语句设置,但这......
  • 05-03 Map Persistent Objects to Database Views(将持久对象映射到数据库视图 )
    MapPersistentObjectstoDatabaseViews(将持久对象映射到数据库视图)CreateaPersistentClass(创建持久类)Createapersistentclass.Theclassnameshouldmatchtheviewname.创建一个持久类。类名应与视图名匹配。AssignthePersistentattributetotheper......
  • 05-04 Basics of Creating Persistent Objects for Existing Data Tables(为现有数据表
    BasicsofCreatingPersistentObjectsforExistingDataTables(为现有数据表创建持久对象的基础知识)ToaccessanexistingdatatableinadatabaseandworkwithitusingthefunctionalityprovidedbyeXpressPersistentObjects(XPO),youneedtocreateap......
  • 05-01 Create a Persistent Object(创建持久对象)
    CreateaPersistentObject(创建持久对象)TheXPOORMcanloadandsavetoadatastoreonlypersistentobjects.XPOORM只能加载持久对象并将其保存到数据存储中。Youmakeyourbusinessobjectspersistentinanyofthefollowingways:您可以通过以下任何方式......
  • 前端数据持久化——Vuex+LocalStorage
    VuexVueX详解_组合式vuex-CSDN博客 LocalStorageLocalStorage是一种WebAPI,它允许网站在用户的本地浏览器中存储和检索数据,而不是将数据存储在服务器上。以下是LocalStorage的详细解析:一、LocalStorage的基本特点本地存储:LocalStorage存储的数据保存在用户的浏览器中,不......
  • 线段树进阶
    线段树进阶目录线段树进阶线段树+贪心/线段树+排序例题:1.洛谷P1607FairShuttleG2.洛谷P1937BarnAllocationG3.洛谷P1972HH的项链线段树+双指针例题:1.洛谷P1712区间线段树+多个标记维护例题:1.洛谷P2572序列操作线段树+二分例题:1.洛谷P4344脑洞治疗仪2.洛谷P2824排......