splay伸展树主要有两种操作形式
(1)正常的二叉树插入形式
功能:a、查找 b、求最大值 c、最小值 d、求前驱 e、求后继 f、删点 g、合并splay树
(这里的删除直接利用splay树的结点下标)
(2)区间形式 (插入是以区间形式插入的)
区间形式的伸展树相当于线段树,支持线段树的所有操作,并且还支持区间插入这个功能,
比如操作区间[a,b],将根设为a-1,根的右孩子设为b+1,那么根的右孩子的左孩子就是所求区间
某个点插入区间也是一个道理
需要注意的是,这里init()自动生成了左右区间,方便之后的操作。注意实际有效的区间范围即可。
(区间删除或者说其他操作,利用的是原序列的下标,再通过函数找到对应的splay结点下标,转换到区间,再对区间删除)
这道题主要是二叉树的插入形式
需要用到 插入 找前驱 找后继 删点 合并 这几个功能
删点就是将所需要删除的点splay到根,去掉联系,合并左右子树即可
合并过程是将左子树的最大键值结点提为根,右子树插入左子树的根即可。
当左子数没有的时候,合并的结果直接是右子树。。
标记一下当前树是动物或者人即可用一棵splay树来完成
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <math.h>
#include <vector>
#include <cstdio>
#include <string>
#include<string.h>
#include <fstream>
#include <iostream>
#include <algorithm>
using namespace std;
#define exp 1e-8
#define INF 0x3f3f3f3f
#define ll long long
#define set(a,b) memset(a,b,sizeof(a));
#define set(a,b) memset(a,b,sizeof(a));
#define for1(a,b) for(int a=1;a<=b;a++)//1---(b)
#define for0(a,b) for(int a=0;a<=b;a++)//0---(b)
void bug(string st="bug")
{cout<<st<<endl;}
template<typename __ll>
inline void READ(__ll &m){
__ll x=0,f=1;char ch=getchar();
while(!(ch>=‘0‘&&ch<=‘9‘)){if(ch==‘-‘)f=-1;ch=getchar();}
while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
m=x*f;
}
template<typename __ll>
inline void read(__ll &m){READ(m);}
template<typename __ll>
inline void read(__ll &m,__ll &a){READ(m);READ(a);}
template<typename __ll>
inline void read(__ll &m,__ll &a,__ll &b){READ(m);READ(a);READ(b);}
const int MAXN=100000+1000;
#define dat int
#define Key_value ch[ch[root][1]][0]
struct splaytree
{
int ch[MAXN][2]; //孩子
int pre[MAXN]; //父亲
dat key[MAXN]; //键值
int size[MAXN]; //大小
int root,tot1; //根 结点大小
int s[MAXN],tot2; //删除用的数组,记录删除了那些点,重复利用删除的点
int kind,ans;
void addnode(int &r,int father,dat k)
{
if(tot2) r=s[tot2--];
else r=++tot1;
ch[r][0]=ch[r][1]=0;
pre[r]=father;
key[r]=k;
size[r]=1;
}
void push_up(int r)
{
if(!r)return ; //添加这句,以防对0结点不小心操作
int lson=ch[r][0],rson=ch[r][1];
size[r]=1+size[lson]+size[rson];
}
void init()
{
kind=-1,ans=0;
root=tot1=tot2=0;
ch[0][0]=ch[0][1]=pre[0]=size[0]=0;
key[0]=-INF;
}
void rotate(int x,int kind)
{
int y=pre[x];
int z=pre[y];
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
if(z) ch[z][ch[z][1]==y] = x;
pre[x]=pre[y];
ch[x][kind]=y;
pre[y]=x;
push_up(y);
}
void splay(int r,int goal) //r是splay的结点下标
{
while(pre[r]!=goal) //各类push_down已经在rotate中执行
{
if(pre[pre[r]]==goal)
{
rotate(r,ch[pre[r]][0]==r);
continue;
}
int y=pre[r];
int z=pre[y];
int kind= ch[z][0]==y;
if(ch[y][kind]==r)
rotate(r,!kind),rotate(r,kind);
else rotate(y,kind),rotate(r,kind);
}
push_up(r);
if(goal==0) root=r;
}
int insert(int &x,int f,int val) //返回插入结点的下标
{
if(x==0)
{
addnode(x,f,val);
int tmp=x;
splay(tmp,0);
return tmp; //如果是这样子插入的话,
} //由于是int &x,splay会将ch[pre[x]]][]修改,导致x也改变了
if(val==key[x])
return x;
if(val<key[x])
return insert(ch[x][0],x,val);
else
return insert(ch[x][1],x,val);
}
void erase(int r) //重复利用删除的结点
{
if(!r)return ;
s[++tot2]=r;
pre[r]=0; //如此就截断了关系了
}
int get_next() //返回后缀的结点下标
{
int r=root;
r=ch[r][1]; //开始使劲靠左找后继
while(ch[r][0])
r=ch[r][0];
return r;
}
int get_pre() //返回前缀的结点下标
{
int r=root;
r=ch[r][0];
while(ch[r][1])
r=ch[r][1];
return r;
}
int get_max(int r) //获得当前树最大键值的结点下标
{
while(ch[r][1])
r=ch[r][1];
return r;
}
void Union(int lroot,int rroot) //合并两课树
{
if(lroot==0) //左子树没有,root直接等于右子树
{
root=rroot;
return ;
}
int r=get_max(lroot); //获得最大的左子树的最大的某一个点
splay(r,0); //并将其设为根
ch[root][1]=rroot; //合并
pre[rroot]=root;
push_up(root);
}
void cut_root(int idx) //砍掉某一个结点,
{
splay(idx,0);
int r=root;
int lroot=ch[r][0];
int rroot=ch[r][1];
pre[lroot]=pre[rroot]=0;
erase(r);
Union(lroot,rroot);
}
int find(int val,int r) //查找,如果找到返回结点下标
{
if(!r) return 0;
if(val==key[r])
return r;
if(val<key[r])
return find(val,ch[r][0]);
return find(val,ch[r][1]);
}
void solve(int val)
{
int r=find(val,root);
if(!r) //没找到同一个值的宠物 人
{
r=insert(root,0,val);
splay(r,0);
int preidx=get_pre();
int nextidx=get_next();
if((preidx!=0&&nextidx==0)||(preidx!=0&&nextidx!=0&&abs(key[preidx]-key[r])<=abs(key[nextidx]-key[r])))
{
ans+=abs(key[preidx]-key[r]);
cut_root(preidx);
}
else
{
ans+=abs(key[nextidx]-key[r]);
cut_root(nextidx);
}
push_up(root);
}
ans%=1000000;
cut_root(r);
push_up(root);
if(size[root]==0)
kind=-1;
}
}t;
int main()
{
int n,a,b,ans;
read(n);
t.init();
while(n--)
{
read(a,b);
if(t.kind==-1||t.kind==a)
t.insert(t.root,0,b),t.kind=a;
else
t.solve(b);
}
printf("%d\n",t.ans);
return 0;
}
时间: 2024-10-29 04:01:43