可持久化(二)

文章目录

  • 【可持久化值域线段树/主席树】
    • 主席树代码
    • 【二维数点】
    • 例题

【可持久化值域线段树/主席树】

P3834 【模板】可持久化线段树 1(主席树)
查询序列区间第k小,静态在线。给定 n 个整数构成的序列,将对于指定的闭区间查询其区间内的第 k 小值。

类似值域线段树上二分求kth的方法,对于[l,r]区间内部的 kth,若有[1,l-1]和[1,r]2个前缀所对应的2棵值域线段树rt0/rt1,也可以通过:

比较 getSZ(rt1->ls) - getSZ(rt0->ls) 和 当前k 的大小关系

来二分答案。

为了构建所有前缀[1,i]对应的动态开点值域线段树,用可持久化的方式依次将a[1…N]加入值域线段树,每次加入都生成一个新版本即可。空间O(NlogN),同时拥有 N棵 值域线段树。注意这里主席树支持在线询问但不支持修改。时间复杂度O(QlogN)。
在这里插入图片描述

主席树代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define ll long longtypedef pair<int,int>P;
const int INF=0x3f3f3f3f;
const int N=200005;
int a[N],b[N],tot=0;
int rt[N],ls[N*20],rs[N*20],sum[N*20];void build(int &o,int l,int r){o=++tot;sum[o]=0;if(l==r)return ;int m=(l+r)>>1;build(ls[o],l,m);build(rs[o],m+1,r);
}void update(int &o,int l,int r,int pre,int p){o=++tot;ls[o]=ls[pre];rs[o]=rs[pre];sum[o]=sum[pre]+1;if(l==r)return ;int m=(l+r)>>1;if(p<=m)update(ls[o],l,m,ls[pre],p);else update(rs[o],m+1,r,rs[pre],p);
}int query(int lr,int rr,int l,int r,int k){if(l==r)return l;int m=(l+r)>>1;int cnt=sum[ls[rr]]-sum[ls[lr]];if(k<=cnt)return query(ls[lr],ls[rr],l,m,k);else return query(rs[lr],rs[rr],m+1,r,k-cnt);
}int main(){int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);b[i]=a[i];}sort(a+1,a+1+n);int nn=unique(a+1,a+1+n)-(a+1);int l,r,k;build(rt[0],1,nn);for(int i=1;i<=n;i++){int x=lower_bound(a+1,a+1+nn,b[i])-a;update(rt[i],1,nn,rt[i-1],x);}while(m--){scanf("%d%d%d",&l,&r,&k);int ans=query(rt[l-1],rt[r],1,nn,k);printf("%d\n",a[ans]);}
}

【二维数点】

这里的可持久化值域线段树支持对一个下标区间[l,r]中值域区间[vl,vr]内的计数/求和等操作,相当与静态二维数点,复杂度1个log。注意这里不支持动态修改。
二维数点就是将(i,a[i])加入到主席树中,比如查询[l,r]中值域区间[vl,vr]中点的数量,在第r个树中求[vl,vr]d的区间和(因为是值域线段树),在第l-1个树中求[vl,vr]的区间和,就用第r个树(tr[r])减去树(tr[l-1])
在这里插入图片描述

#include<bits/stdc++.h>
#define LL long long
#define INF (1<<20)
#define MAXN 100005
#define getSZ(p) (p?p->sz:0)
#define getLSZ(p) (p?getSZ(p->ls):0)
#define getL(p) (p?p->ls:0)
#define getR(p) (p?p->rs:0)
using namespace std;struct Node{int l,r,sz;Node *ls, *rs;void update(){sz = getSZ(ls) + getSZ(rs);}} pool[50*MAXN], *rt[MAXN];int top = 0;
int N,Q;Node* copyNode(Node* rt){Node *p = pool + (++top);*p = *rt;return p;
}Node* newNode(int l, int r){Node *p = pool + (++top);p->l = l; p->r = r;return p;
}Node* insert(Node* rt, int l, int r, int x){Node *p;if(rt) p = copyNode(rt);else p = newNode(l,r);++p->sz;if(p->l==x && p->r==x) return p;int mid = (l + r)/2;if(x<=mid) p->ls = insert(p->ls, l, mid, x);else p->rs = insert(p->rs, mid+1, r, x);p->update();return p;
}int query(Node* pL, Node* pR, Node* p0, Node* p1, int k){if(pR && pR->l==pR->r) return pR->l;if(pL && pL->l==pL->r) return pL->l;int k1 = getLSZ(pL) + getLSZ(pR) - getLSZ(p0) - getLSZ(p1);if(k1 >= k) return query(getL(pL), getL(pR), getL(p0), getL(p1), k);else return query(getR(pL), getR(pR), getR(p0), getR(p1), k - k1);
}int a[MAXN], c[MAXN];
vector<int> adj[MAXN];
bool vis[MAXN];
int anc[MAXN][21], dep[MAXN];void dfs(int u, int fa){vis[u] = 1;rt[u] = insert(rt[fa], 1, N, a[u]);for(int j=1;j<=20;j++){if(dep[u] <= (1<<j)) break;anc[u][j] = anc[anc[u][j-1]][j-1];}int v;for(int k=0;k<adj[u].size();k++){v = adj[u][k];if(vis[v]) continue;dep[v] = dep[u] + 1; anc[v][0] = u;dfs(v, u);}
}int lca(int u, int v){if(dep[u] < dep[v]) swap(u,v);for(int j=20;j>=0;j--){if(dep[anc[u][j]] >= dep[v]){u = anc[u][j];}}if(u == v) return u;for(int j=20;j>=0;j--){if(anc[u][j] != anc[v][j]){u = anc[u][j];v = anc[v][j];}}return anc[u][0];
} int main(){scanf("%d%d", &N, &Q);for(int i=1;i<=N;i++) scanf("%d", &a[i]);memcpy(c,a,sizeof(a));sort(c+1,c+1+N);for(int i=1;i<=N;i++){a[i] = lower_bound(c+1,c+1+N,a[i]) - c;}int u,v;for(int i=1;i<N;i++){scanf("%d%d", &u, &v);adj[u].push_back(v);adj[v].push_back(u);}dep[1] = 1;dfs(1,0);int k, z, lastans = 0;while(Q--){scanf("%d%d%d", &u, &v, &k);u ^= lastans;z = lca(u, v);lastans = c[query(rt[u], rt[v], rt[z], rt[anc[z][0]], k)];printf("%d\n", lastans);}return 0;
}

例题

P2633 Count on a tree
P3567 [POI2014]KUR-Couriers

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET Core / C# 开发 IOT 嵌入式设备的个人见解

( .NET Core 七龙珠 )一、IOT 平台的支持先看国内优秀的云计算IOT平台(不含QQ互联、小米IOT等针对特定产品的开发者平台&#xff0c;仅列出部分云计算厂商的IOT平台)阿里云 IOThttps://iot.aliyun.com/华为物联网https://developer.huawei.com/ict/cn/site-iot-next腾讯云 物联…

合成小丹(dp+二进制按位或+结论)

problem 给定 nnn 个在 [0,2ω−1][0,2^\omega-1][0,2ω−1] 内的整数。执行下面操作两种操作共 n−1n-1n−1 次&#xff1a; 选择两个整数 x,yx,yx,y 从数列中删去&#xff0c;并加入 ⌊x∣y2⌋\lfloor\frac{x|y}{2}\rfloor⌊2x∣y​⌋&#xff0c;这里的 | 表示按位或。选择…

P2633 Count on a tree

P2633 Count on a tree 题意&#xff1a; 给定一棵 n 个节点的树&#xff0c;每个点有一个权值。有 m 个询问&#xff0c;每次给你 u,v,k&#xff0c;你需要回答 u xor last 和 v 这两个节点间第 k 小的点权。 其中last 是上一个询问的答案&#xff0c;定义其初始为 0&#…

[NewLife.XCode]增量累加

NewLife.XCode是一个有10多年历史的开源数据中间件&#xff0c;支持nfx/netstandard&#xff0c;由新生命团队(2002~2019)开发完成并维护至今&#xff0c;以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析&#xff0c;蕴含多年开发经验于其中&#xff0…

King of Range

King of Range 题意&#xff1a; 给你n个数&#xff0c;有m个询问&#xff0c;每次询问一个x&#xff0c;问有多少个区间的最大值减最小值大于x 题解&#xff1a; 我一开始的想法 st表实现区间最大减最小&#xff0c;利用二分来找这个区间范围&#xff0c;复杂度O(nmlogn)&…

膜拜大丹(结论+二元环)

problem 有两个国家&#xff0c;国家 AAA 有 nnn 座城市&#xff0c;国家 BBB 有 mmm 座城市&#xff0c;两个国家间有若干条单向航线。 具体地&#xff0c;有长度为 nnn 的数组 aaa 和长度为 mmm 的数组 bbb。国家 AAA 的第 iii 座城市有单向航线可以到达国家 BBB 的 1∼ai1…

Jewels

Jewels 题意&#xff1a; 你的坐标是(0,0,0)&#xff0c;有m个宝物&#xff0c;分别坐标是是(xi,yi,zi),它的z坐标以每秒下沉vi深度&#xff0c;你每次获取一个宝物的费用是两者的距离的平方&#xff0c;每秒只能获取一个宝物&#xff0c;从第0秒开始&#xff0c;问获取所有宝…

[NewLife.XCode]脏数据

NewLife.XCode是一个有10多年历史的开源数据中间件&#xff0c;支持nfx/netstandard&#xff0c;由新生命团队(2002~2019)开发完成并维护至今&#xff0c;以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析&#xff0c;蕴含多年开发经验于其中&#xff0…

[学习笔记] 二分图基础定理的相关证明

最小点集覆盖最大匹配 最小点集覆盖&#xff1a;选出最少的点使得每条边都至少有一个端点被选。 先证最小点集覆盖 ≥\ge≥ 最大匹配 假设最大匹配为 xxx&#xff0c;即有 xxx 条边两两之间没有公用点。 光覆盖这些边就要用到 xxx 个点。 “不少于”已证。 再证最小点集覆盖 …

Boxes

Boxes 题意&#xff1a; 有n个盒子&#xff0c;每个盒子里要么是黑球&#xff0c;要么是白球&#xff0c;你可以花C的代码得知剩下所有盒子中黑球数量和白球数量&#xff0c;(只是知道总数量&#xff0c;并不知道具体哪个盒子里是什么)&#xff0c;你可以可以花费wi的代价开第…

Double Strings

Double Strings 题意&#xff1a; 给你s和t两个字符串&#xff0c;在其中选出两个等长的子序列(可以不连续)a&#xff0c;b&#xff0c;满足a的字典序严格小于b的字典序&#xff0c;问方案数,答案mod(1e97) 题解&#xff1a; 好的方案的构成是一段相同的前缀一个不同的字符…

你真的了解用户吗?-浅谈《用户画像》的意义和方法

作者&#xff1a;陈炯关于作者系统集成项目管理高级工程师某大型国有银行高级质量管理师从事IT项目管理工作十余年具有丰富的开发与管理经验公司内部敏捷转型的发起者之一深度参与敏捷实践与总结大学校园里流传最广的一句话是什么&#xff1f;“防火防狼防师兄”。为什么师兄这…

[学习笔记] 二次剩余

二次剩余 对于素数 ppp 和数 aaa&#xff0c;满足 (a,p)1(a,p)1(a,p)1。&#xff08;注意 aaa 不一定小于 ppp&#xff09; 若 ∃xx2≡a(modp)\exist_{x}\ x^2\equiv a\pmod p∃x​ x2≡a(modp)&#xff0c;则称 aaa 是模 ppp 意义下的二次剩余&#xff0c;xxx 称为该二次剩余…

Script Lab 续:为 Officejs 开发配置 VSCode 环境

垫场AA&#xff1a;深度&#xff1a;从 Office 365 新图标来看微软背后的设计新理念--------------------------------------------------前期01&#xff1a;尝试&#xff1a;Script Lab&#xff0c;快速 Office 365 开发工具前期02&#xff1a;尝试&#xff1a;Script Lab&…

P3567 [POI2014]KUR-Couriers

P3567 [POI2014]KUR-Couriers 题意&#xff1a; 给一个长度为 n 的正整数序列 a。共有 m 组询问&#xff0c;每次询问一个区间 [l,r] &#xff0c;是否存在一个数在 [l,r]中出现的次数严格大于一半。如果存在&#xff0c;输出这个数&#xff0c;否则输出 0。 题解&#xff1…

[WC 2022 Day3 zmy] Od deski do deski(dp)

设 fi:1∼if_{i}:1\sim ifi​:1∼i 能否分成若干个首尾相同的区间 则有 fiORj<i(fj−1∧ajai)f_{i}\text{OR}_{j<i}(f_{j-1}\wedge a_ja_i)fi​ORj<i​(fj−1​∧aj​ai​)。 这是最原始的暴力 dpdpdp&#xff0c;时间 O(n2m)O(n^2m)O(n2m)。 事实上&#xff0c;这…

编程方式重启 ASP.NET Core 网站

点击上方蓝字关注“汪宇杰博客”常言道&#xff0c;多喝热水&#xff0c;重启试试。有时候当应用工作不正常&#xff0c;重启也许能解决问题。但是程序员通常接触不到服务器系统权限。而运维人员和公司流程经常人为制造麻烦阻止我们去重启应用。老实的程序员不善言辞交际&#…

可持久化3--可持久化01Trie

01Trie 可持久化 01Trie 的方式和可持久化值域线段树的方式是相似的&#xff0c;只是以 01字典树 的方式来维护值域。一般用来解决异或相关的能够按位贪心的题目。 其实就是将可持久化线段树中的操作嫁接到01Trie中&#xff0c;这样就是解决任意一个区间内的问题。 例题&…

AGC044E Pandom Pawn(期望+凸包)

最开始我们先旋转一下这张桌子&#xff0c;使得 A1An1max⁡{Ai}A_1A_{n1}\max\{A_i\}A1​An1​max{Ai​}。 这是非常有效的&#xff0c;因为我们把环就变成链&#xff0c;只要到达了链的任意一端 1/n11/n11/n1 就肯定会结束游戏。 定义 Ei:E_i:Ei​: 从 iii 开始游戏&#xf…

.NET Core 容器化调查

前几天在微信朋友圈做了一个简单的调查&#xff0c;参与人数有500人&#xff0c;调查结果如下&#xff1a;使用K8S的比例非常类似于2017年初我在公众号里针对.NET Core的使用情况的比例。.NET Core是针对云原生应用开发而重新设计的一个平台&#xff0c;.NET Core借鉴了.NET Fr…