题意: 给你n个数,每次先输出第i大的数的位置(如果有多个,选下标小的那个),然后每次将第i个位置到第i大的数所在位置之间的数进行翻转。

思路:输入的数组可能有多个相同的值,我们可以进行两次排序把数组的值变为1---n(表示第几大)。

在建伸展树的时候我们可以顺便用pos[i]记录第i大的数的节点标号。

对于第i次操作,我们用col[]数组记录翻转标记,每次先把第i大的节点pos[i]旋转到根,那么它的位置为i+左儿子的个数。然后左儿子打上翻转标记,最后删除根。

注意:下放懒惰标记时只要交换左右儿子的节点标号就可以了,也正因为这个原因,

下放函数的位置记得要放在没有引用任何左右儿子信息之前, 这跟区间其它操作最大的区别。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define L ch[x][0]
#define R ch[x][1]
const int maxn = 100005;
int pos[maxn]; //pos[i]表示第i大的数的节点的标号
int n;
struct node {int a, id;bool operator <(const node &t) const {return id < t.id;}
}p[maxn];
bool cmp(const node &a, const node &b) {return a.a < b.a || (a.a == b.a && a.id < b.id);
}
struct splayTree {int sz[maxn], ch[maxn][2], pre[maxn];bool col[maxn];int root, tot;void down(int x) {if(col[x]) {col[L] ^= 1;col[R] ^= 1;swap(L, R);col[x] = 0;}}void up(int x) {sz[x] = sz[L] + sz[R] + 1;}void rotate(int &x, int f) {int y = pre[x], z = pre[y];down(y); down(x);ch[y][!f] = ch[x][f];pre[ch[x][f]] = y;pre[x] = pre[y];if(pre[x]) ch[z][ch[z][1] == y] = x;ch[x][f] = y;pre[y] = x;up(y);}void splay(int &x, int g) {while(pre[x] != g) {int y = pre[x], z = pre[y];down(z); down(y); down(x);//不是区间翻转的题,这里的down可以不写,因为rotate里面有down, 但区间翻转要先down在去旋转,因为左右儿子会改变if(z == g) rotate(x, ch[y][0] == x);else {int f = (ch[z][0] == y);ch[y][!f] == x ? rotate(y, f) : rotate(x, !f);rotate(x, f);}}up(x);if(!g) root = x;}int find(int k) {int x = root;while(sz[L]+1 != k) {down(x);if(sz[L]>= k) x = L;else {k -= sz[L]+1;x = R;}}return x;}void rto(int k, int g) {int x = root;while(1) {down(x);if(sz[L]+1 == k) break;if(sz[L]>= k) x = L;else {k -= sz[L]+1;x = R;}}splay(x, g);}void newNode(int &x, int m, int fa) {x = ++tot;pos[p[m].a] = x;pre[x] = fa;sz[x] = 1;L = R = 0;col[x] = 0;}void build(int &x, int l, int r, int fa) {if(l > r) return;int m = (l + r) >> 1;newNode(x, m, fa);build(L, l, m-1, x);build(R, m+1, r, x);up(x);}void init(int n) {tot = 0;int i;//数字可能相等,可以把数字预处理成1--nfor(i = 1; i <= n; i++) {scanf("%d", &p[i].a);p[i].id = i;}sort(p+1, p+n+1, cmp);for(i = 1; i <= n; i++)p[i].a = i;sort(p+1, p+n+1);build(root, 1, n, 0);}void print(int x) {down(x);printf("x: %d lson: %d rson: %d fa: %d lsz: %d rsz: %d\n", x, L, R, pre[x], sz[L], sz[R]);if(L)print(L);if(R)print(R);}void debug() {printf("root = %d\n", root);print(root);}void solve() {for(int i = 1; i < n; i++) {splay(pos[i], 0);    //把值为i的节点旋到根int x = root;printf("%d ", sz[L]+i);down(x); col[L] ^= 1; down(L); //根down,根的左儿子打翻转标记if(sz[L]) {    //有左儿子rto(sz[L], root); //把左儿子的最右边的点旋到根//删除根,根的左儿子代替根,新根的右儿子还是原根的右儿子,但父亲要修改root = L;ch[root][1] = R;pre[root] = 0;pre[R] = root;}else { //没有左儿子,直接把右儿子拉到根上来root = ch[root][1];pre[root] = 0;}up(root);}printf("%d\n", n);//最后只剩一个节点时一定是最后一个, 特判一下。}
}spt;
int main() {int i;while( ~scanf("%d", &n) && n) {spt.init(n);spt.solve();}return 0;
}

[置顶] hdu 1890 伸展树区间翻转相关推荐

  1. POJ 2777 ZOJ 1610 HDU 1698 --线段树--区间更新

    直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 ...

  2. hdu 1698(线段树区间更新)

    解题思路:线段树区间更新水题. #include<iostream> #include<cstdio> #include<cstring> using namesp ...

  3. BZOJ 3223: Tyvj 1729 文艺平衡树-Splay树(区间翻转)模板题

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 6881  Solved: 4213 [Submit][S ...

  4. HDU - 4578Transformation——线段树+区间加法修改+区间乘法修改+区间置数+区间和查询+区间平方和查询+区间立方和查询

    [题目描述] HDU - 4578Transformation Problem Description Yuanfang is puzzled with the question below: The ...

  5. hdu 5367(线段树+区间合并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5367 官方题解: 对于求"高山脉"长度,可以利用线段树.树节点中保存左高度连续长度 ...

  6. hdu 5124(线段树区间更新+lazy思想)

    http://acm.hdu.edu.cn/showproblem.php?pid=5124 题意:区间覆盖次数问题. 解题思路:线段树水之. #include<iostream> #in ...

  7. hdu 3954(线段树区间更新)

    转载标记处:http://www.cnblogs.com/wang-jue/articles/2920341.html 思路:这道题所得到的经验与每个英雄的等级有关,一般的可能就用线段树一直更新到每一 ...

  8. hdu 1806线段树 区间合并

    #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> us ...

  9. 伸展树算法c语言,数据结构之伸展树详解

    1. 概述 二叉查找树(Binary Search Tree,也叫二叉排序树,即Binary Sort Tree)能够支持多种动态集合操作,它可以用来表示有序集合.建立索引等,因而在实际应用中,二叉排 ...

最新文章

  1. freemarker中运算符_如何在Web应用系统表示层开发中应用Velocity模板技术
  2. C++关键字积累——持续更新
  3. 如何跟各种人解释什么是产品经理
  4. vr降噪器英文是什么_什么是VR体验馆设备?
  5. php如何抓取一行的内容,提取一行作为对象 - PHP 7 中文文档
  6. 省选+NOI 第六部分 技巧与思想
  7. 机器学习1.2 ---参数学习
  8. excel两个表格数据对比_两个Excel表格合并,最有水平的处理方法
  9. 云课堂智慧职教网页版登录入口_云课堂智慧职教网页版登录入口-云课堂智慧职教app官网版下载-XP软件园...
  10. 可视化管理|省时省力加速查询,建造基于 Hightopo 智慧档案馆
  11. E盾V60原版网络验证包含个人动手改IP地址源码软件加密一机一码
  12. 万圣节到了,来讲鬼故事吧!(大家可以在回复中继续讲)
  13. Node.js git命令
  14. 内含扩容源码的面试题,目标是手写HashMap!
  15. vue3.x 使用jsplumb进行拖拽连线
  16. 微信公众号自定义菜单直接跳转到小程序指定页面
  17. 高用户体验,减少跳出率
  18. 从全国首日票房破百万看零售商家的线下营销
  19. 从零开始实现k线图走势图绘制(iOS理论篇)
  20. 使用ultraISO 制作多种系统的启动U盘和文件U盘

热门文章

  1. flutter - 如何在Dart/Flutter中将某些元素从一个Map复制到新Map中?
  2. 最容易理解的计算机网络 基础知识概论(下)
  3. plsql窗口文件怎么找回_电脑文件丢失怎么找回?知道原因和方法很关键
  4. html 如何让div刷新页面,页面刷新.html
  5. java多线程有几种实现方法_Java多线程之间实现通讯
  6. 深圳上海场 | 神策 2019 数据驱动大会「PPT 下载」新鲜出炉!
  7. phpstrom 里面的 文件修改后 的*怎样设置
  8. Exp3 免杀原理与实践 20154320 李超
  9. 原型设计真的对用户体验那么重要吗?
  10. 网络间谍又添利器:新型远程访问木马Trochilus