题目

  点这里看题目。

分析

  最妙的地方在于,这道题其实是用一种数据结构模拟另一种数据结构

  我们需要维护深度和树的结构,以下对于每个操作进行分别讨论。

插入一个新节点

  可以发现,这个新节点一定会成为自己的前驱或者后继中深度较大者的儿子

  然后可以更新深度和树的结构。

单旋最小值

  发现树会有如下的变化:

    如果自己有儿子,那么它只会是自己的右儿子;旋转后,它会接到自己原先的父亲上

    除了自己的儿子以外,其它的节点的深度都会 +1

    
原先的根变成了最小值的儿子
根随后变成最小值

  单旋最大值同理分析。

单旋最小值并删除

  先模拟好单旋的修改,然后考虑旋转后的变化:

    所有节点深度 -1

    
断开最小值和它的右儿子的边,根变为它的右儿子


  单旋最大值并删除同理分析。

  发现树的深度的修改实际上可以理解为值域上一段区间的加减,因此可以用权值线段树维护;前驱后继也可以顺便用它维护了。

  中途我们需要用 map 来维护树的形态,或者离散化之后直接存下来也可以。

  时间复杂度:\(O(n\log_2|V|)\)。

代码

#include <map>
#include <cstdio>
using namespace std; const int up = 1e9/*4*/;
const int MAXN = 1e5 + 5, MAXLOG = 30, MAXS = MAXN * MAXLOG/*205*/; template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
} template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
} map<int, int> fa, ch[2]; int siz[MAXS], dep[MAXS], tag[MAXS], lch[MAXS], rch[MAXS];
int tot, rt, sgrt; void upt( const int x ) { siz[x] = siz[lch[x]] + siz[rch[x]]; }
void add( const int x, const int v ) { dep[x] += siz[x] * v, tag[x] += v; }
void normalize( const int x ) { if( tag[x] ) add( lch[x], tag[x] ), add( rch[x], tag[x] ), tag[x] = 0; } void setNode( int &u, const int l, const int r, const int pos, const int v )
{
if( ! u ) u = ++ tot;
if( l == r ) { siz[u] += v; return ; }
int mid = l + r >> 1; normalize( u );
if( pos <= mid ) setNode( lch[u], l, mid, pos, v );
else setNode( rch[u], mid + 1, r, pos, v );
upt( u );
} void update( int &u, const int l, const int r, const int segL, const int segR, const int v )
{
if( ! u ) u = ++ tot;
if( segL <= l && r <= segR ) { add( u, v ); return ; }
int mid = l + r >> 1; normalize( u );
if( segL <= mid ) update( lch[u], l, mid, segL, segR, v );
if( mid < segR ) update( rch[u], mid + 1, r, segL, segR, v );
upt( u );
} int query( const int u, const int l, const int r, const int segL, const int segR )
{
if( ! u ) return 0;
if( segL <= l && r <= segR ) return siz[u];
int mid = l + r >> 1, ret = 0; normalize( u );
if( segL <= mid ) ret += query( lch[u], l, mid, segL, segR );
if( mid < segR ) ret += query( rch[u], mid + 1, r, segL, segR );
return ret;
} int Kth( const int u, const int l, const int r, const int rnk )
{
if( l == r ) return l;
int mid = l + r >> 1; normalize( u );
if( rnk <= siz[lch[u]] ) return Kth( lch[u], l, mid, rnk );
return Kth( rch[u], mid + 1, r, rnk - siz[lch[u]] );
} int getDep( const int u, const int l, const int r, const int pos )
{
if( l == r ) return dep[u];
int mid = l + r >> 1; normalize( u );
if( pos <= mid ) return getDep( lch[u], l, mid, pos );
return getDep( rch[u], mid + 1, r, pos );
} int Kth( const int rnk ) { if( rnk <= 0 ) return -1; if( rnk > siz[sgrt] ) return up + 1; return Kth( sgrt, 1, up, rnk ); }
int getDep( const int id ) { if( id < 0 || id > up ) return -0x3f3f3f3f; return getDep( sgrt, 1, up, id ); } int getMx( const int u, const int l, const int r )
{
if( l == r ) return l;
int mid = l + r >> 1; normalize( u );
if( siz[rch[u]] ) return getMx( rch[u], mid + 1, r );
return getMx( lch[u], l, mid );
} int getMn( const int u, const int l, const int r )
{
if( l == r ) return l;
int mid = l + r >> 1; normalize( u );
if( siz[lch[u]] ) return getMn( lch[u], l, mid );
return getMn( rch[u], mid + 1, r );
} int rotMn()
{
int id = getMn( sgrt, 1, up ), rig = ch[1][id], y = fa[id];
if( rt == id ) return 1;
if( rig ) fa[rig] = y; fa[rt] = id, fa[id] = 0;
ch[1][id] = rt, ch[0][y] = rig, rt = id;
int ret = getDep( id );
update( sgrt, 1, up, y, up, 1 );
update( sgrt, 1, up, id, id, -ret + 1 );
return ret;
} int rotMx()
{
int id = getMx( sgrt, 1, up ), lef = ch[0][id], y = fa[id];
if( rt == id ) return 1;
if( lef ) fa[lef] = y; fa[rt] = id, fa[id] = 0;
ch[0][id] = rt, ch[1][y] = lef, rt = id;
int ret = getDep( id );
update( sgrt, 1, up, 1, y, 1 );
update( sgrt, 1, up, id, id, -ret + 1 );
return ret;
} int main()
{
int op, k, N;
read( N );
while( N -- )
{
read( op );
if( op == 1 )
{
read( k ), setNode( sgrt, 1, up, k, 1 );
if( siz[1] == 1 )
{
fa[rt = k] = 0, update( sgrt, 1, up, k, k, 1 );
puts( "1" );
continue;
}
int rnk = query( sgrt, 1, up, 1, k );
int pre = Kth( rnk - 1 ), suf = Kth( rnk + 1 );
int dpre = getDep( pre ), dsuf = getDep( suf );
if( dpre > dsuf ) fa[k] = pre, ch[1][pre] = k, update( sgrt, 1, up, k, k, dpre + 1 );
else fa[k] = suf, ch[0][suf] = k, update( sgrt, 1, up, k, k, dsuf + 1 );
write( getDep( k ) ), putchar( '\n' );
}
if( op == 2 ) write( rotMn() ), putchar( '\n' );
if( op == 3 ) write( rotMx() ), putchar( '\n' );
if( op == 4 )
{
int ans = rotMn(), tmp = rt, y = ch[1][tmp];
update( sgrt, 1, up, tmp + 1, up, -1 );
update( sgrt, 1, up, tmp, tmp, - ans );
if( y ) fa[y] = 0; ch[1][tmp] = 0, rt = y;
setNode( sgrt, 1, up, tmp, -1 );
write( ans ), putchar( '\n' );
}
if( op == 5 )
{
int ans = rotMx(), tmp = rt, y = ch[0][tmp];
update( sgrt, 1, up, 1, tmp - 1, -1 );
update( sgrt, 1, up, tmp, tmp, -ans );
if( y ) fa[y] = 0; ch[0][tmp] = 0, rt = y;
setNode( sgrt, 1, up, tmp, -1 );
write( ans ), putchar( '\n' );
}
}
return 0;
}

最新文章

  1. 学习3ds max插件开发过程中的一些小结
  2. ios上架报错90080,90087,90209,90125 解决办法
  3. OAuth2集成
  4. Windows下一个比较完美的线程池实现(使用线程池实现的Http上传下载实现)
  5. bzoj 1012 维护一个单调数列
  6. Mysql连接测试代码
  7. WPF窗口长时间无人操作鼠标自动隐藏
  8. oracle建用户
  9. 巧用system函数个性化屏幕显示
  10. Python的参数模块OptionParser说明
  11. 【模拟】XMU 1599 斐波那契汤
  12. 带项目的一些体会以及合格的 Leader 应该具备什么特质?(转)
  13. Oracle 去掉重复字符串
  14. CSS.05 -- 规避脱标 定位的盒子居中、CSS标签规范、溢出隐藏、内容移除(网页优化)、CSS精灵图
  15. ASP.NET Core 从 gitlab-ci 环境变量读取配置
  16. Linux批量结束、杀死进程
  17. 用OZ工具制作openstack镜像
  18. Recurrent NN vs Recursive NN
  19. LeetCode题解之Univalued Binary Tree
  20. jQuery中attr和prop方法的区别说明

热门文章

  1. mysql小白系列_09 mysql性能优化关键点
  2. mysql基本操作汇总
  3. 新概念英语三 新东方主讲Lesson1
  4. 杨辉三角(hdu2032)——有待完善
  5. python 读取txt文件
  6. Excel中遇到的一些问题——持续更新
  7. 第3章 衡量线性回归的指标:MSE,RMSE,MAE
  8. iOS开发判断手机号及其运营商
  9. 剑指Offer之变态跳台阶
  10. dsPIC33EP单片机的PPS(外设引脚选择)