P5494 题解
来一发 \(O(\log n)\) 线性空间的解法。
考虑通过只维护线段树叶子节点的虚树的方法压缩空间,考虑记录下每个节点的编号,然后通过异或完求最低位的 \(1\) 的方式求出 LCA 的深度,然后记录下 LCA 右端点的编号。在回收节点的时候可以释放储存右端点编号的空间,但是这里为了方便就不这样做了。
具体维护方法看下面的代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 4e5+114;
int tot;
stack<int> brush;
struct Node{
int ls,rs;
int sum;
int l,r;
}tree[maxn<<1];
int clone(){
int New;
if(brush.size()>0){
New=brush.top();
brush.pop();
}
else{
New=++tot;
}
tree[New].l=tree[New].r=tree[New].sum=tree[New].ls=tree[New].rs=0;
return New;
}
int root[maxn],val[maxn],lg[maxn];
inline int w(int x){
int l=1,r=(1<<18),v=1,res=0;
while(l!=r){
int mid=(l+r)>>1;
if(x<=mid){
r=mid;
}
else{
l=mid+1;
res+=v;
}
v<<=1;
}
return res;
}
inline pair<int,int> LCA(int u,int v){
if(val[u]==0) val[u]=w(u);
if(val[v]==0) val[v]=w(v);
int f=val[u]^val[v];
f=f&(-f);
int len=1<<(18-lg[f]);
int pos=(u-1)/len+1;
val[(pos-1)*len+1]=(f-1)&val[u];
return make_pair((pos-1)*len+1,pos*len);
}
inline void pushup(int x){
tree[x].sum=tree[tree[x].ls].sum+tree[tree[x].rs].sum;
}
inline void add(int x,int pos,int v){
int mid=(tree[x].l+tree[x].r)>>1;
if(pos<=mid){
if(tree[x].ls==0){
int y=clone();
tree[x].ls=y;
tree[y].sum+=v;
tree[y].l=tree[y].r=pos;
pushup(x);
return ;
}
else{
if(tree[tree[x].ls].l==tree[tree[x].ls].r){
if(tree[tree[x].ls].l==pos){
tree[tree[x].ls].sum+=v;
pushup(x);
return ;
}
pair<int,int> lca=LCA(pos,tree[tree[x].ls].l);
int y=clone();
tree[y].l=lca.first;
tree[y].r=lca.second;
int A=y;
int B=tree[x].ls;
int z=clone();
tree[z].sum+=v;
tree[z].l=tree[z].r=pos;
int C=z;
tree[x].ls=A;
if(tree[B].l>tree[C].l) swap(B,C);
tree[A].ls=B;
tree[A].rs=C;
pushup(A);
pushup(x);
return ;
}
else{
if(pos>tree[tree[x].ls].r||pos<tree[tree[x].ls].l){
pair<int,int> lca=LCA(pos,tree[tree[x].ls].l);
int y=clone();
tree[y].l=lca.first;
tree[y].r=lca.second;
int A=y;
int B=tree[x].ls;
int z=clone();
tree[z].sum+=v;
tree[z].l=tree[z].r=pos;
int C=z;
tree[x].ls=A;
if(tree[B].l>tree[C].l) swap(B,C);
tree[A].ls=B;
tree[A].rs=C;
pushup(A);
pushup(x);
}
else{
add(tree[x].ls,pos,v);
pushup(x);
return ;
}
}
}
}
else{
if(tree[x].rs==0){
int y=clone();
tree[x].rs=y;
tree[y].sum+=v;
tree[y].l=tree[y].r=pos;
pushup(x);
return ;
}
else{
if(tree[tree[x].rs].l==tree[tree[x].rs].r){
if(tree[tree[x].rs].r==pos){
tree[tree[x].rs].sum+=v;
pushup(x);
return ;
}
pair<int,int> lca=LCA(pos,tree[tree[x].rs].l);
int y=clone();
tree[y].l=lca.first;
tree[y].r=lca.second;
int A=y;
int B=tree[x].rs;
int z=clone();
tree[z].sum+=v;
tree[z].l=tree[z].r=pos;
int C=z;
tree[x].rs=A;
if(tree[B].l>tree[C].l) swap(B,C);
tree[A].ls=B;
tree[A].rs=C;
pushup(A);
pushup(x);
return ;
}
else{
if(pos<tree[tree[x].rs].l||pos>tree[tree[x].rs].r){
pair<int,int> lca=LCA(pos,tree[tree[x].rs].l);
int y=clone();
tree[y].l=lca.first;
tree[y].r=lca.second;
int A=y;
int B=tree[x].rs;
int z=clone();
tree[z].sum+=v;
tree[z].l=tree[z].r=pos;
int C=z;
tree[x].rs=A;
if(tree[C].l>tree[B].l) swap(C,B);
tree[A].ls=C;
tree[A].rs=B;
pushup(A);
pushup(x);
}
else{
add(tree[x].rs,pos,v);
pushup(x);
return ;
}
}
}
}
}
inline int query(int x,int l,int r){
int lt=tree[x].l;
int rt=tree[x].r;
if(x==0) return 0;
if(rt<l||r<lt){
return 0;
}
if(l<=lt&&rt<=r){
return tree[x].sum;
}
int res=0,mid=(lt+rt)>>1;
res+=query(tree[x].ls,l,r);
res+=query(tree[x].rs,l,r);
return res;
}
int merge(int a,int b){
if(a==0||b==0) return a+b;
if((tree[a].r-tree[a].l+1)<(tree[b].r-tree[b].l+1)) swap(a,b);
if(tree[a].l==tree[b].l&&tree[a].r==tree[b].r){
if(tree[a].l==tree[a].r){
tree[a].sum+=tree[b].sum;
brush.push(b);
return a;
}
int L=tree[b].ls,R=tree[b].rs;
brush.push(b);
tree[a].ls=merge(tree[a].ls,L);
tree[a].rs=merge(tree[a].rs,R);
pushup(a);
return a;
}
if(tree[a].l<=tree[b].l&&tree[b].r<=tree[a].r){
int mid=(tree[a].l+tree[a].r)>>1;
if(tree[b].l<=mid) tree[a].ls=merge(tree[a].ls,b);
else tree[a].rs=merge(tree[a].rs,b);
pair<int,int> lca=LCA(tree[tree[a].ls].l,tree[tree[a].rs].l);
tree[a].l=lca.first,tree[a].r=lca.second;
pushup(a);
return a;
}
if(tree[a].l>tree[b].l) swap(a,b);
if(tree[a].r<tree[b].l){
pair<int,int> lca=LCA(tree[a].l,tree[b].l);
int y=clone();
tree[y].l=lca.first;
tree[y].r=lca.second;
tree[y].ls=a;
tree[y].rs=b;
pushup(y);
return y;
}
else{
int L=tree[b].ls,R=tree[b].rs;
brush.push(b);
tree[a].ls=merge(tree[a].ls,L);
tree[a].rs=merge(tree[a].rs,R);
pushup(a);
return a;
}
}
inline void maintain(int &x){
if(tree[x].l!=1||tree[x].r!=(1<<18)){
int y=clone();
tree[y].l=1,tree[y].r=(1<<18);
int mid=(tree[y].l+tree[y].r)>>1;
if(!x){
x=y;
return ;
}
if(tree[x].r<=mid){
tree[y].ls=x;
}
else{
tree[y].rs=x;
}
pushup(y);
x=y;
}
return ;
}
inline void split(int &x,int &y,int l,int r){
if(!x) return ;
int lt=tree[x].l,rt=tree[x].r;
if(rt<l||r<lt) return ;
if(l<=lt&&rt<=r){
y=x;
x=0;
return ;
}
if(!y) y=clone();
split(tree[x].ls,tree[y].ls,l,r);
split(tree[x].rs,tree[y].rs,l,r);
if(tree[y].ls==0&&tree[y].rs==0){
brush.push(y);
y=0;
}
else if(tree[y].ls==0){
brush.push(y);
y=tree[y].rs;
}
else if(tree[y].rs==0){
brush.push(y);
y=tree[y].ls;
}
else{
pair<int,int> lca=LCA(tree[tree[y].ls].l,tree[tree[y].rs].l);
tree[y].l=lca.first,tree[y].r=lca.second;
pushup(y);
}
if(tree[x].ls==0&&tree[x].rs==0){
brush.push(x);
x=0;
}
else if(tree[x].ls==0){
brush.push(x);
x=tree[x].rs;
}
else if(tree[x].rs==0){
brush.push(x);
x=tree[x].ls;
}
else{
pair<int,int> lca=LCA(tree[tree[x].ls].l,tree[tree[x].rs].l);
tree[x].l=lca.first,tree[x].r=lca.second;
pushup(x);
}
return ;
}
inline int kth(int x,int k){
if(tree[x].l==tree[x].r) return tree[x].l;
if(k<=tree[tree[x].ls].sum) return kth(tree[x].ls,k);
else return kth(tree[x].rs,k-tree[tree[x].ls].sum);
}
void init(int pos){
root[pos]=clone();
tree[root[pos]].l=1;
tree[root[pos]].r=(1<<18);
}
int n,m;
int cnt;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
for(int i=0;i<=18;i++) lg[1<<i]=i;
cin>>n>>m;
cnt++;
init(cnt);
for(int i=1;i<=n;i++){
int x;
cin>>x;
add(root[cnt],i,x);
}
while(m--){
int opt;
cin>>opt;
if(opt==0){
int x,y,z;
cin>>x>>y>>z;
cnt++;
split(root[x],root[cnt],y,z);
maintain(root[x]);
maintain(root[cnt]);
}
else if(opt==1){
int x,y;
cin>>x>>y;
root[x]=merge(root[x],root[y]);
maintain(root[x]);
}
else if(opt==2){
int x,y,z;
cin>>x>>y>>z;
add(root[x],z,y);
}
else if(opt==3){
int x,y,z;
cin>>x>>y>>z;
cout<<query(root[x],y,z)<<'\n';
}
else{
int x,y;
cin>>x>>y;
if(tree[root[x]].sum<y){
cout<<"-1\n";
}
else{
cout<<kth(root[x],y)<<'\n';
}
}
}
return 0;
}
P5494 题解的更多相关文章
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
- JSOI2016R3 瞎BB题解
题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...
随机推荐
- Swift File Manager 三种文件路径查找方法对比
目录 1. 引言 2. 三种文件路径查找方法 2. 1 NSSearchPathForDirectoriesInDomains(_:_:_:) 2.2 urls(for:in:) 2.3 url(fo ...
- gin-vue-admin 03 项目打包上线
目录 作者视频 思路 环境要求 1. 配置nginx 2.打包前台vue代码 3.打包后台go代码 4. 上传代码到服务器 5. 后台运行power 6. 访问后台 开发场景: 1. nginx 配置 ...
- 2023年Clion插件推荐
目录 搜素位置 插件 background-image plus 背景图片插件 Rainbow Brackets 彩虹括号 Xcode-Dark Theme 界面主题 Grep Console 日志颜 ...
- Garnet:微软官方基于.NET开源的高性能分布式缓存存储数据库
前言 前不久Redis宣布从 Redis 7.4 开始,将原先比较宽松的 BSD 源码使用协议修改为 RSALv2 和 SSPLv1 协议,该协议变化意味着Redis不再开源.今天给大家分享一款完全开 ...
- 自动化发布ansible以及awx相关(持续更新)
一 本文章只介绍ansible的基础知识以及一些组织架构,如何批量的处理等 首先一套部署发布任务在ansible里面都是以role的形式展现,并在执行命令的时候执行role入口以及主机列表 例如:an ...
- 零代码零硬件玩转华为云IoT,基于设备联动实时监控设备
本文分享自华为云社区<一键守护,实时洞察:华为云IoT设备联动,智能感知设备状态变化,精准触发告警通知[零代码零硬件玩转华为云IoT]>,作者:周周的奇妙编程. 前言 在前面我们已经体验过 ...
- 二叉树的遍历(BFS、DFS)
二叉树的遍历(BFS.DFS) 本文分为以下部分: BFS(广度优先搜索) DFS(深度优先搜索) 先序遍历 中序遍历 后序遍历 总结 BFS(广度优先搜索) 广度优先搜索[^1](英语:Breadt ...
- 008. gitlab代码克隆与推送
推送配置 gitlab需要推送的客户端sshkey添加到gitlab服务器中 node1 推送配置 centos node1: [root@node1 ~]# cat ~/.ssh/id_rsa.pu ...
- redis cluaster (redis分布式集群 redis分片集群)
redis cluaster (redis分布式集群) 高可用: 在搭建集群时,会为每一个分片的主节点,对应一个从节点,实现slaveof的功能,同时当主节点down,实现类似于sentinel的自动 ...
- mediaserverd
1.mediaserverd是什么 mediaserverd(/usr/sbin/mediaserverd)是被root进程launchd启动的一个后台(daemon)进程,其描述文件为com.app ...