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 ...
随机推荐
- Linux查看文件指定行数内容与查找文件内容
Linux查看文件指定行数内容 1.tail date.log 输出文件末尾的内容,默认10行 tail -20 date.log 输出最后20行的内容 tail -n -20 date.log 输出 ...
- Unity新的MeshData API学习
在新版本的Unity中提供了MeshDataArray和MeshData等多个API,使Mesh数据操作支持多线程:以更好的支持DOTS. API文档:https://docs.unity3d.com ...
- 使用XCA自制CA证书并签发https证书
序言 本文目的是使公司内网部署的Web可以使用https的方式访问 现有部署的系统有用域名访问,有用IP访问,但都是用http的方式 所以打算在公司内网部署统一的CA证书,并可以自己签发对应的域名和I ...
- RoslynPad的简单使用
虽说Visual Studio被我们戏称宇宙最强IDE,但是平常随手写段C#代码进行验证或者语法校验,属于牛刀小试了,显然轻量级C#编辑器更适合这种场景,目前较为流行的则是一代神器 LINQPad,但 ...
- Django模板templates
1.模板文件的路径配置 2.模板中变量替换 3.变量渲染之深度查询 4.内置过滤器 过滤器的语法: {{obj|过滤器名称:过滤器参数}} 内置过滤器: 过滤器例子: 5.注释 6.多行注释 7.if ...
- Tkinter禁止用户调整窗口尺寸大小
禁止用户调整窗口尺寸大小的方式: root.resizable(False,False) 例子: from tkinter import * from tkinter import ttk impor ...
- Dubbo实战教程
"Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC(一种远程调用) 分布式服务框架(SOA),致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案." ...
- 深入理解Vue 3:计算属性与侦听器的艺术
title: 深入理解Vue 3:计算属性与侦听器的艺术 date: 2024/5/30 下午3:53:47 updated: 2024/5/30 下午3:53:47 categories: 前端开发 ...
- 企业级nginx内核优化篇
1. cpu核心配置 方法1: worker_processes auto; 自动调用[推荐] 方法2: worker_processes 4; 手工配置 检查CPU核心:yum install nu ...
- 知乎x-zse-96逆向分析
声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 目标网站 aHR0cHM6 ...