#include<bits/stdc++.h>
using namespace std;
#define N 1005
struct node
{int l, r; // 左右儿子节点编号int val; // 节点值int key; // 随机key值int siz; // 子树大小int rev; // 翻转标记
} tr[N];
int n, root, idx;// 节点数,根节点编号,当前节点编号
// 构造
int newnode(int v)
{tr[++idx].val = v;tr[idx].key = rand() /*随机化key值*/;tr[idx].siz = 1;tr[idx].rev = 0;return idx;
}
// 向上更新
void pushup(int p)
{tr[p].siz = tr[tr[p].l].siz /*左侧节点数*/ + tr[tr[p].r].siz + /*右侧节点数*/ 1 /*本身*/;
}
// 向下传递懒标记
void pushdown(int p)
{// 交换左右子树swap(tr[p].l, tr[p].r);// 下传标记给子节点if (tr[p].l) tr[tr[p].l].rev ^= 1;if (tr[p].r) tr[tr[p].r].rev ^= 1;// 清除当前节点标记tr[p].rev = 0;
}// 根据val分裂
void split1(int p, int v, int &x, int &y)
{if (!p) // 当前节点为空时处理{x = y = 0;return;}if (tr[p].val <= v){x = p;split1(tr[p].r /*新当前节点*/,v /*保持阈值不变*/,tr[p].r /*将结果x挂到当前节点的右子树*/,y /*输出大于v的部分*/);}else{y = p;split1(tr[p].l /*新当前节点*/,v /*保持阈值不变*/,x /*输出小于等于v的部分*/,tr[p].l /*将结果y挂到当前节点的左子树*/);}pushup(p);
}
// 根据size分裂
// 将树p按前k个节点分裂为x(左树)和y(右树)
void split2(int p, int k, int &x, int &y)
{if (!p){x = y = 0;return;}else{pushdown(p); // 处理延迟标记// 计算左子树容量是否足够if (tr[tr[p].l].siz < k) // 左子树容量不足,需要向右子树分裂{x = p;// 递归右子树,更新剩余需要分裂的数量:k - 左子树大小 - 当前节点split2(tr[p].r, k - tr[tr[p].l].siz - 1, tr[p].r, y);}else // 左子树容量足够,向左子树分裂{y = p;// 递归左子树,保持分裂数量k不变split2(tr[p].l, k, x, tr[p].l);}pushup(p); // 更新当前节点子树大小}
}// 合并
int merge(int x, int y) // 合并两个子树(x树所有节点值 <= y树所有节点值)
{// 任意子树为空时直接返回非空子树if (!x || !y)return x + y;// 根据随机key值决定父子关系(保持堆性质)if (tr[x].key < tr[y].key) // x作为父节点{tr[x].r = merge(tr[x].r, y); // 将y合并到x的右子树pushup(x); // 更新x的子树大小return x; // 返回合并后的根节点}else // y作为父节点{tr[y].l = merge(x, tr[y].l); // 将x合并到y的左子树pushup(y); // 更新y的子树大小return y; // 返回合并后的根节点}
}
//启发式合并
int merge2(int x,int y)
{if(!x||!y)return x|y;if(tr[x].key<tr[y].key)swap(x,y);int a,b;split2(x,tr[y].siz,a,b);tr[y].l=merge2(a,tr[y].l);tr[y].r=merge2(b,tr[y].r);pushup(y);
}
//删除
void del(int v)
{int x, y, z;split1(root, v, x, z); // 把树分成小于等于v和大于v的两部分split1(x, v - 1, x, y); // 把小于等于v的部分分成小于v和等于v的两部分y = merge(tr[y].l, tr[y].r); // 把等于v的部分合并成一个节点root = merge(merge(x, y), z); // 把小于v和大于v的两部分合并成一个树
}
//插入 首先生成新节点(函数newnode)
void insert(int val)
{int x, y;// 按照val分裂成左子树x(<=val)和右子树y(>val)split1(root, val, x, y);// 将新节点合并到左子树末端,再与右子树合并形成新根root = merge(merge(x, newnode(val)), y);
}
//查找第k个 整体二分思想 看看去左边还是右边找
int getk(int p,int k)
{// 目标在左子树的情况if(k<=tr[tr[p].l].siz)return getk(tr[p].l,k);// 当前节点正好是第k个节点(左子树节点数 + 1)if(k==tr[tr[p].l].siz+1)return p;// 目标在右子树的情况,调整k值:k - 左子树大小 - 当前节点return getk(tr[p].r,k-tr[tr[p].l].siz-1);
}
//查找这东西的前驱(我也不知道这东西有什么用)
void getpre(int v)
{int x,y;split1(root,v,x,y);cout<<tr[getk(x,tr[x].siz)].val<<endl; root=merge(x,y);
}
//查找这东西的后继(我也不知道这东西有什么用*2)
void getsuc(int v)
{int x,y;split1(root,v,x,y);cout<<tr[getk(y,1)].val<<endl;root=merge(x,y);
}//对区间进行操作
void modify(int l,int r)
{/*总体:分割 对节点操作 合上*/int x,y,z;split2(root,l-1,x,y);split2(y,r-l+1,y,z);//你想进行的操作 例如翻转,求和等等//这里用反转当例子tr[y].rev^=1;root=merge(merge(x,y),z);return;
}