TYVJ1729文艺平衡树

传送门:http://tyvj.cn/Problem_Show.aspx?id=1729

文艺平衡树

From admin

背景 Background

此为平衡树系列第二道:文艺平衡树

描述 Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

输入格式 InputFormat

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n

输出格式 OutputFormat

输出一行n个数字,表示原始序列经过m次变换后的结果

样例输入 SampleInput [复制数据]

5 3
1 3
1 3
1 4

样例输出 SampleOutput [复制数据]

4 3 2 1 5

数据范围和注释 Hint

n,m<=100000

做法:Splay对区间的操作、lazy标记。 我一直没懂这个splay的操作,对区间[a,b]的操作,首先把a-1splay到树根,然后再把b+1旋转到树根的右子树。这个很好理解,但是我一开始写的是直接T[i].s[v>T[i].v]访问,一直不对,一直很纳闷,后来模拟了一下,才发现真正有效的是splay的排名,lazy标记下传后,左右子树被交换,但默认的排名未变。即第i号元素不一定就是i。

Codes:(再次orz squarefk)

 1 #include <set>
 2 #include <cmath>
 3 #include <queue>
 4 #include <cstdio>
 5 #include <cstdlib>
 6 #include <cstring>
 7 #include <iostream>
 8 #include <algorithm>
 9 using namespace std;
10 const int N = 100010;
11 #define fa(i) (T[i].p)
12 #define Ch1 (T[i].s[0])
13 #define Ch2 (T[i].s[1])
14 #define Loc(i) (T[fa(i)].s[1]==i)
15 #define Sets(a,b,c) {T[a].s[c] = b;fa(b) = a;}
16 #define For(i,n) for(int i=1;i<=n;i++)
17 #define Rep(i,l,r) for(int i=l;i<=r;i++)
18
19 struct tnode{
20     int s[2],size,p,V,flag;
21 }T[N];
22
23 int ttot,l,r,n,m,root;
24
25 void Pushdown(int i){
26     if(T[i].flag){
27         if(Ch1) T[Ch1].flag ^= 1;
28         if(Ch2) T[Ch2].flag ^= 1;
29         swap(Ch1,Ch2);
30         T[i].flag = 0;
31     }
32 }
33
34 void Build(int l,int r,int p,int &i){
35     if(l>r) return;
36     int m = ( l + r ) >> 1;
37     T[i=++ttot].V = m;
38     T[i].p = p; T[i].size = 1;
39     Build(l,m-1,i,Ch1);
40     Build(m+1,r,i,Ch2);
41     T[i].size = T[Ch1].size + T[Ch2].size + 1;
42 }
43
44 void Rot(int x){
45     int y = fa(x) , z = fa(y);
46     Pushdown(y);Pushdown(x);
47     int lx = Loc(x) , ly = Loc(y);
48     Sets(y,T[x].s[!lx],lx);
49     Sets(z,x,ly);
50     Sets(x,y,!lx);
51     T[y].size = T[T[y].s[0]].size + T[T[y].s[1]].size + 1;
52 }
53
54 void Splay(int i,int goal){
55     while(fa(i)!=goal){
56         if(fa(fa(i))!=goal) Rot(fa(i));
57         Rot(i);
58     }
59     T[i].size = T[Ch1].size + T[Ch2].size + 1;
60     if(!goal) root = i;
61 }
62
63 int Find(int i,int rank){
64     Pushdown(i);
65     if(T[Ch1].size + 1 == rank) return i;
66     else if(T[Ch1].size>= rank) return Find(Ch1,rank);
67     else                        return Find(Ch2,rank-T[Ch1].size-1);
68 }
69
70 void OUT(int i,int rank){
71     if(!i) return;
72     Pushdown(i);
73     OUT(Ch1,rank);
74     rank+=T[Ch1].size+1;
75     if((rank!=1)&&(rank!=n+2)){
76         if(rank==n+1) printf("%d\n",T[i].V);
77         else          printf("%d ",T[i].V);
78     }
79     OUT(Ch2,rank);
80 }
81
82
83 int main(){
84     scanf("%d%d",&n,&m);
85     Build(0,n+1,0,root);
86     For(i,m){
87         scanf("%d%d",&l,&r);
88         Splay(Find(root,l),0);
89         Splay(Find(root,r+2),root);
90         T[T[T[root].s[1]].s[0]].flag ^= 1;
91     }
92     OUT(root,0);
93     return 0;
94 }

TYVJ1729文艺平衡树

时间: 2024-10-11 05:12:58

TYVJ1729文艺平衡树的相关文章

[BZOJ3223][tyvj1729]文艺平衡树

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 5356  Solved: 3163 [Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列

[BZOJ3223] [Tyvj1729] 文艺平衡树 (splay)

Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数 接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n Output 输出一行n个数字,表示原始序列经过m次变换后的结果 Sample Input 5 3 1 3

[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护的标准,而处理区间问题时,维护平衡树的应该是每个位置的下标,所以平衡树中序遍历时应该是当前区间的样子.例如: {1 2 3 4 5}翻转区间1 3,则中序遍历应该输出{3,2,1,4,5}. 提供splay和无旋Treap的做法. splay做法: 1 #include<bits/stdc++.h>

[题解]bzoj 3223 文艺平衡树

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3884  Solved: 2235[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次

3223: Tyvj 1729 文艺平衡树

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3473  Solved: 1962[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次

BZOJ 3223: Tyvj 1729 文艺平衡树

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3629  Solved: 2053[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次

Tyvj P1729 文艺平衡树 Splay

题目: http://tyvj.cn/p/1729 P1729 文艺平衡树 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 此为平衡树系列第二道:文艺平衡树 描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入格式 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n)  m表示翻转操作次数

AC日记——文艺平衡树 洛谷 P3391

文艺平衡树 思路: splay翻转操作模板: 虚拟最左最右端点,然后每次都把l翻转到root,r+2翻转到root的右节点: 然后在r+2的左节点上打标记: 标记需要在旋转,rank,print时下放: 建树需要用完全平衡二叉树: 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define m

P3391 【模板】文艺平衡树(Splay)

题目背景 这是一道经典的Splay模板题--文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入输出格式 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,?n?1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r