来一发 \(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 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. 《最新出炉》系列入门篇-Python+Playwright自动化测试-44-鼠标操作-上篇

    1.简介 前边文章中已经讲解过鼠标的拖拽操作,今天宏哥在这里对其的其他操作进行一个详细地介绍和讲解,然后对其中的一些比较常见的.重要的操作单独拿出来进行详细的介绍和讲解. 2.鼠标操作语法 鼠标操作介 ...

  2. ubuntu系统下安装php7.4

    目录 一.下载/更新php源 二.安装php7.4 三.修改配置 3.1 修改www.conf 文件 四.配置域名 五.nginx的配置文件 5.1 sock方式和nginx配合工作 5.2监听900 ...

  3. Linux下vim的常用命令总结

    vim按d表示剪切 按dd剪切一行 vim命令:命令模式 /关键字 n继续向下查找 vim的多行注释: 1.按ctrl + v进入 visual block模式 2.按上下选中要注释的行 3.按大写字 ...

  4. VNC远程控制软件是什么?有没有更好的远程桌面控制解决方案?

    看官老爷们,你们是否需要远程访问或远程支持解决方案?来了解下VNC吧. 什么是VNC? VNC是虚拟网络计算(VNC)是一种远程桌面共享技术,用于从世界任何地方远程访问和控制计算机. VNC的工作原理 ...

  5. 4G EPS 中的各种唯一标识

    目录 文章目录 目录 电信运营商的唯一标识:PLMN.MCC 与 MNC 移动用户的唯一标识:IMSI.MSIN 与 MSISDN/MDN 移动用户的唯一临时标识:TMSI.GUTI 与 GUMMEI ...

  6. jenkens

    [root@mcw01 ~]$ ls .jenkins/ config.xml jenkins.install.UpgradeWizard.state nodeMonitors.xml secret. ...

  7. 【漏洞复现】Apache RocketMQ 代码注入漏洞(CVE-2023-37582)

    产品介绍 Apache RocketMQ是美国阿帕奇(Apache)基金会的一款轻量级的数据处理平台和消息传递引擎. 漏洞概述 Apache RocketMQ 存在代码注入漏洞,该漏洞源于当 Name ...

  8. 复现禅道V17.4的sql注入漏洞

    漏洞详情 简述:禅道是第一款国产的开源项目管理软件,它的核心管理思想基于敏捷方法 scrum,内置了产品管理和项目管理,同时又根据国内研发现状补充了测试管理.计划管理.发布管理.文档管理.事务管理等功 ...

  9. go高并发之路——go语言如何解决并发问题

    一.选择GO的原因 作为一个后端开发,日常工作中接触最多的两门语言就是PHP和GO了.无可否认,PHP确实是最好的语言(手动狗头哈哈),写起来真的很舒爽,没有任何心智负担,字符串和整型压根就不用区分, ...

  10. java 执行 javascript 代码

    package com.ruoyi.project.front.controller; import java.math.BigDecimal; import java.util.*; import ...