不得不说,做过最爽的树套树————

由于有了区间操作,我们很容易把区间看成一棵平衡树,对他进行插入,那么外面一层就是平衡树了,这就与我们之前所见到的不同了。我们之前所见到的大多数是线段树套平衡树而此题中插入时坐标会改变即必须对其找到合适的顺序,而线段树无疑是不支持动态插入的,他维护的是一个静态区间(因为插入一个点整个区间的二分结构可能全部改变,这用他就无法通过区间二分来维护信息了)。所以说我们必须来进行平衡树套线段树,那么平衡树就需要维护区间,而线段树就需要维护权值,之前我们的树套树,在外边一个静态区间线段树里面每个节点都有这个点dfs序所对应区间里的数的有序排列,在这里我们用平衡树来维护区间,那么对于里面的点,YY一下,也是对应于父子关系的一段区间,但我们无法将里面的点有序化,但是我们得到了一个可视且可用的一段取值区间这样我们就可以用动态开点来维护权值信息,一般的平衡树像Splay Treap都需要旋转操作而每次旋转里面的线段树维护的权值信息都会随着父子关系的改变而改变,每次都需要新的线段树(合并也行),常数大到飞起(Treap插入乘个log,Spaly插入乘个log查询log2,虽然看起来没那么差甚至根由更优,但是想一想常数),那么替罪羊就要来当大佬了(表示不会无旋Treap),这样只有每次重构才会将重建(合并)线段树,大约有㏒₂n次重建。

空间复杂度:替罪羊n;线段树如果不修改  ∑(i=1 ~log2n)n*[log2n-∑(j=1~log2n-i+1)[(2i-1)/2i]],平均每个点152个,

如果修改的话2*n+∑(i=1~log₂n-1)[17-∑(j=1~log₂n-j+2)[(2i-1)/2i]]*n*2,平均每个点280个

这样的话我们就需要回收空间了,不仅是在重建的时候,也必须得是在修改的时候(别问我为什么这么说QAQ),把他维持到152个以内

时间复杂度:一开始的点用O(n+nlog₂²n),每次插入O(log₂²n),修改O(log₂²n),查询:每一层被选中的点和根(不要忘了我们是在分平衡树千万不要忘了中间那个点)的个数不超过四个(这个我不会理性的证,我先感性的证一下:1.你把这棵树建出来,开始在同一深度找,找到五个的时候怎么也找不到2.这么吊的数据结构查询怎么也得是log级别的啊),所以就是O(log₂n+log₂3n),总重建O(log₂n*(n+∑(i=1 ~log2n)n*[log2n-∑(j=1~log2n-i+1)[(2i-1)/2i]]+n*log²n))大约10*log²n*n

所以总时间复杂度:O(q*log₂3n)估大一点200000*173也就是109由于每个点10s也就行了

然而人傻自带大常数........

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAXN 140100
#define inf 70000
using namespace std;
inline int read()
{
int s=;
char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')
{
s=(s<<)+(s<<)+ch-;
ch=getchar();
}
return s;
}
const double alpha=0.75;
struct Tree
{
Tree *ch[];
int size,l,r,mid;
}*null,*stack[*MAXN],pool[*MAXN],*now[MAXN];
int Now[MAXN],num,Num;
int list[MAXN],len;
int top;
struct ScapeGoat_Tree
{
ScapeGoat_Tree *ch[];
int size,key;
Tree *root;
bool bad()
{
return size*alpha+<ch[]->size||size*alpha+<ch[]->size;
}
void pushup()
{
size=ch[]->size+ch[]->size+;
}
}*Null,*root,*lst[MAXN],node[MAXN];
int sz;
inline void Init()
{
null=pool;
null->size=null->l=null->r=null->mid=;
null->ch[]=null->ch[]=null;
for(int i=;i<(*MAXN);i++)stack[++top]=pool+i;
Null=node;
Null->size=Null->key=;
Null->ch[]=Null->ch[]=Null;
Null->root=null;
root=Null;
}
inline Tree *New(int l,int r)
{
Tree *p=stack[top--];
p->l=l;
p->r=r;
p->mid=(l+r)>>;
p->size=;
p->ch[]=p->ch[]=null;
return p;
}
inline ScapeGoat_Tree *New(int key)
{
ScapeGoat_Tree *p=&node[++sz];
p->ch[]=p->ch[]=Null;
p->size=;
p->key=key;
p->root=null;
return p;
}
void recovery(Tree *p)
{
if(p==null)return;
recovery(p->ch[]);
stack[++top]=p;
recovery(p->ch[]);
}
void travel(ScapeGoat_Tree *p)
{
if(p==Null)return;
travel(p->ch[]);
lst[++len]=p;
list[len]=p->key;
recovery(p->root);
p->root=null;
travel(p->ch[]);
}
void ins(Tree *&p,int key,int l,int r)
{
if(p==null)p=New(l,r);
p->size++;
if(p->l==p->r)return;
if(p->mid<key) ins(p->ch[],key,p->mid+,r);
else ins(p->ch[],key,l,p->mid);
}
ScapeGoat_Tree *divide(int l,int r)
{
if(l>r)return Null;
int mid=(l+r)>>;
for(int i=l;i<=r;i++)ins(lst[mid]->root,list[i],,inf);
lst[mid]->ch[]=divide(l,mid-);
lst[mid]->ch[]=divide(mid+,r);
lst[mid]->pushup();
return lst[mid];
}
void Ins(ScapeGoat_Tree *p,int key,int pos)
{
ins(p->root,key,,inf);
if(p->ch[]->size+==pos)
{
p->key=key;
return;
}
if(p->ch[]->size>=pos)Ins(p->ch[],key,pos);
else Ins(p->ch[],key,pos-p->ch[]->size-);
}
inline void rebuild(ScapeGoat_Tree *&p)
{
len=;
travel(p);
p=divide(,len);
}
ScapeGoat_Tree **insert(ScapeGoat_Tree *&p,int key,int pos)
{
if(p==Null)
{
p=New(key);
ins(p->root,key,,inf);
return &Null;
}
p->size++;
ins(p->root,key,,inf);
ScapeGoat_Tree **ret;
if(p->ch[]->size+>=pos)ret=insert(p->ch[],key,pos);
else ret=insert(p->ch[],key,pos-p->ch[]->size-);
if(p->bad())ret=&p;
return ret;
}
inline void Insert(int key,int pos)
{
ScapeGoat_Tree **p=insert(root,key,pos);
if(*p!=Null)rebuild(*p);
}
inline int find(int pos)
{
ScapeGoat_Tree *p=root;
while()
if(p->ch[]->size+==pos)return p->key;
else if(p->ch[]->size>=pos)p=p->ch[];
else pos-=p->ch[]->size+,p=p->ch[];
}
void del(Tree *&p,int key)
{
p->size--;
if(p->l==p->r)
{
if(p->size==)
{
stack[++top]=p;
p=null;
}
return;
}
del(p->ch[p->mid<key],key);
if(p->size==)
{
stack[++top]=p;
p=null;
}
}
void Del(ScapeGoat_Tree *p,int pos,int key)
{
del(p->root,key);
if(p->ch[]->size+==pos)return;
if(p->ch[]->size>=pos)Del(p->ch[],pos,key);
else Del(p->ch[],pos-p->ch[]->size-,key);
}
int rank(Tree *p,int key)
{
if(p==null)return ;
if(p->l==p->r)return ;
if(key<=p->mid)return rank(p->ch[],key);
else return p->ch[]->size+rank(p->ch[],key);
}
void pre(ScapeGoat_Tree *p,int l,int r)
{
if(p==Null)return;
if(l<=&&p->size<=r)
{
now[++num]=p->root;
return;
}
if(l<=p->ch[]->size)pre(p->ch[],l,r);
if(l<=p->ch[]->size+&&r>=p->ch[]->size+)Now[++Num]=p->key;
if(p->ch[]->size+<r)pre(p->ch[],l-p->ch[]->size-,r-p->ch[]->size-);
}
inline int Rank(int x)
{
int ans=;
for(int i=;i<=num;i++)
ans+=rank(now[i],x);
for(int i=;i<=Num;i++)
if(x>Now[i])ans++;
else break;
return ans;
}
int lastans=;
inline void work1()
{
int x=read()^lastans,y=read()^lastans,k=read()^lastans;
if(x>y)x^=y^=x^=y;
num=Num=;
pre(root,x,y);
sort(Now+,Now+Num+);
int l=,r=inf,ans=;
while(l<=r)
{
int mid=(l+r)>>;
int tmp=Rank(mid)+;
if(tmp<=k)
ans=mid,l=mid+;
else
r=mid-;
}
lastans=ans;
printf("%d\n",ans);
}
inline void work2()
{
int x=read()^lastans,val=read()^lastans;
Del(root,x,find(x));
Ins(root,val,x);
}
inline void work3()
{
int x=read()^lastans,val=read()^lastans;
Insert(val,x);
}
int main()
{
Init();
int n=read();
for(int i=;i<=n;i++)
{
list[++len]=read();
lst[len]=New(list[len]);
}
root=divide(,len);
int Q=read();
while(Q--)
{
char s[];
scanf("%s",s);
if(s[]=='Q')work1();
if(s[]=='M')work2();
if(s[]=='I')work3();
}
return ;
}

【bzoj3065】: 带插入区间K小值 详解——替罪羊套函数式线段树的更多相关文章

  1. [BZOJ3065]带插入区间K小值 解题报告 替罪羊树+值域线段树

    刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值 ...

  2. BZOJ3065 带插入区间K小值 || 洛谷P4278

    这是一道让我崩溃的题...... 然鹅洛谷上时限被改然后只有20分......好像所有人都被卡了(雾) 由于替罪羊树不是依靠旋转操作而是依靠暴力重构的方式维护树的平衡,所以我们可以考虑使用替罪羊树套区 ...

  3. 【函数式权值分块】【块状链表】bzoj3065 带插入区间K小值

    显然是块状链表的经典题.但是经典做法的复杂度是O(n*sqrt(n)*log^2(n))的,出题人明确说了会卡掉. 于是我们考虑每个块内记录前n个块的权值分块. 查询的时候差分什么的,复杂度就是O(n ...

  4. bzoj3065: 带插入区间K小值

    无聊来写了下 一开始发现树高是O(n)的,然后就MLE了,进去看了下发现没有重构! 看了半天发现调用错了函数 然后进去又发现不满足sz = ch[0]->sz + ch[1]->sz + ...

  5. 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树

    经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...

  6. 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树

    [BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...

  7. bzoj 3065: 带插入区间K小值 替罪羊树 && AC300

    3065: 带插入区间K小值 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 1062  Solved: 253[Submit][Status] Des ...

  8. 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树

    题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...

  9. BZOJ 3065 带插入区间K小值(sag套线段树)

    3065: 带插入区间K小值 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 4696  Solved: 1527[Submit][Status][Di ...

随机推荐

  1. Day22-Django之缓存

    由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5 ...

  2. 【spring】- springmvc 工作原理

    原理 本质是将DispatcherServlet及关联的Spring上下文环境的初始化工作织入Servlet的生命周期内,将外部WEB请求转换为Spring Bean能处理的形式,然后将处理后的结果借 ...

  3. 【转】ubuntu16.04安装ncurses-devel

    在ubuntu16.04中编译内核时,使用make menuconfig发生错误,说没有安装ncurses-devel. 使用apt install ncurses-devel命令安装该库,没有,然后 ...

  4. WEB入门.八 背景特效

    学习内容 background属性 CSS Sprite 技术 滑动门技术 能力目标 使用background设置网页背景 使用Sprites制作平滑投票特效 使用滑动门技术实现Tab菜单 本章简介 ...

  5. 3532: [Sdoi2014]Lis 最小字典序最小割

    3532: [Sdoi2014]Lis Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 865  Solved: 311[Submit][Status] ...

  6. Webpack + React 开发 01 HelloWorld

    1.项目依赖 安装所需要依赖的其它第三方开源库,项目依赖如下: "dependencies": { "babel-core": "^6.21.0&qu ...

  7. MySQL基本了解与使用

    MySQL的相关概念介绍 MySQL 为关系型数据库(Relational Database Management System), 这种所谓的"关系型"可以理解为"表格 ...

  8. bzoj 3224

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 16656  Solved: 7255[Submit][St ...

  9. Java入门:Java IO概括

    I/O 问题是任何编程语言都无法回避的问题,可以说 I/O 问题是整个人机交互的核心问题,因为 I/O 是机器获取和交换信息的主要渠道.在当今这个数据大爆炸时代,I/O 问题尤其突出,很容易成为一个性 ...

  10. 「Vue」vue cli3中axios的基本用法

    1.安装axiosnpm i axios -S2.main.js中设置import axios from 'axios'Vue.prototype.$axios = axiosPS:这里有个小坑,ax ...