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 ...
随机推荐
- windows版 navicat_15.0.18 安装
视频安装地址: https://www.ghpym.com/ghvideo07.html 一.下载安装包 下载地址(百度网盘): 链接:https://pan.baidu.com/s/1MIZfmS5 ...
- 深度学习框架火焰图pprof和CUDA Nsys配置指南
注:如下是在做深度学习框架开发时,用到的火焰图pprof和 CUDA Nsys 配置指南,可能对大家有一些帮助,就此分享.一些是基于飞桨的Docker镜像配置的. 一.环境 & 工具配置 0. ...
- 美团二面:SpringBoot读取配置优先级顺序是什么?
引言 Spring Boot作为一种轻量级的Java应用程序框架,以其开箱即用.快速搭建新项目的特性赢得了广大开发者的青睐.其核心理念之一就是简化配置过程,使开发者能够快速响应复杂多变的生产环境需求. ...
- WEB服务与NGINX(7)-实现自定义错误页面
1. 自定义错误页面 error_page code ... [=[response]] uri; 定义错误页,以指定的响应状态码进行响应,此指令由ngx_http_index_module模块提供 ...
- 2020年9月至10月 Splashtop 新功能
Splashtop 已为 Splashtop Business Access.Splashtop Remote Support.Splashtop SOS 和 Splashtop On-Prem ...
- Linux 磁盘、CPU、内存获取脚本
脚本 脚本 #!/bin/bash # 获取要监控的本地服务器IP地址 IP=`/usr/sbin/ifconfig | grep inet | grep -vE 'inet6|127.0.0.1' ...
- java获取Linux和window系统多网卡mac地址和IP
public static List<Map<String, String>> getMacAndIp() throws SocketException { List<M ...
- 容器的监控:使用cAdvisor,weavescope监控容器
目录 一.系统环境 二.前言 三.容器监控的原理 四.使用docker stats监控容器 五.部署cadvisor监控容器 六.部署weavescope监控容器 一.系统环境 服务器版本 docke ...
- 算法金 | 详解过拟合和欠拟合!性感妩媚 VS 大杀四方
大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今天我们来战 过拟合和欠拟合,特别是令江湖侠客闻风丧胆的 过拟合,简称过儿, Emmm ...
- css3 浏览器前缀 线型渐变 过渡属性
css3:没有形成正式版 每个浏览器商,为了能对css3属性形成一个更好的支持,浏览器形成自己一套语法规范,一些css属性,如果想在浏览器上形成支持,有时候需要添加浏览器前缀 谷歌前缀:-webkit ...