HDU 1890:Robotic Sort(Splay)

http://acm.hdu.edu.cn/showproblem.php?pid=1890

题意:有一个无序序列,经过不断地翻转,使得最后的序列是一个升序的序列,而且如果相同数字要使在原本序列靠前的在前面。对于每一个位置,输出于哪个位置翻转。

思路:想通了之后其实挺简单的,不过挺巧妙。一开始先记录每一个位的pos,并对数组升序排序,然后我们从小到大枚举数组里的元素,对于每个元素,我们可以知道:i 就是翻转后应当在序列中的位置,a[i].pos就是它在原序列的位置。这个时候,我们只要在建树的时候利用中序遍历就是原数组的样子的性质,让节点的值就是它在原数组的位置,即建一个新的节点的时候,x 就是在原数组中的编号,例如样例:3 4 5 1 6 2,那么对应的节点的值就是 1 2 3 4 5 6 了。然后对于每一个询问,我们知道了它在原序列的位置,我们将它的位置(即节点本身的值)旋转到根节点,那么它的左子树的 sz 就是它目前所在的位置(因为一开始多了一个节点),然后再对 目标位置 和 所在的位置进行区间翻转,就可以完成了。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <string>
  6 #include <cmath>
  7 #include <queue>
  8 #include <vector>
  9 using namespace std;
 10 #define INF 0x7fffffff
 11 #define lson ch[x][0]
 12 #define rson ch[x][1]
 13 #define keytree ch[ch[root][1]][0]
 14 #define rootkey ch[root][1]
 15 #define N 300000
 16 struct node
 17 {
 18     int val, id;
 19 }a[N];
 20 struct SplayTree {
 21     int num[N], sz[N], fa[N], ch[N][2], root, rev[N];
 22     int n;
 23
 24     void PushUp(int x) {
 25         sz[x] = sz[lson] + sz[rson] + 1;
 26     }
 27
 28     void PushDown(int x) {
 29         if(rev[x]) {
 30             swap(lson, rson);
 31             if(lson) rev[lson] ^= 1;
 32             if(rson) rev[rson] ^= 1;
 33             rev[x] = 0;
 34         }
 35     }
 36
 37     int NewNode(int f, int k, int kind) {
 38         int x = k;
 39         fa[x] = f;
 40         rev[x] = ch[x][0] = ch[x][1] = 0;
 41         sz[x] = 1; ch[f][kind] = x;
 42         return x;
 43     }
 44
 45     void Build(int l, int r, int &x, int f, int kind) {
 46         if(l > r) return ;
 47         int m = (l + r) >> 1;
 48         x = NewNode(f, m, kind);
 49         Build(l, m - 1, ch[x][0], x, 0);
 50         Build(m + 1, r, ch[x][1], x, 1);
 51         PushUp(x);
 52     }
 53
 54     void Init() {
 55         root = 0;
 56         ch[0][0] = ch[0][1] = fa[0] = rev[0] = sz[0] = 0;
 57         root = NewNode(0, n + 1, 0);
 58         rootkey = NewNode(root, n + 2, 1);
 59         sz[root] = 2;
 60         Build(1, n, keytree, rootkey, 0);
 61         PushUp(rootkey); PushUp(root);
 62     }
 63
 64     void Rotate(int x, int kind) {
 65         int y = fa[x], z = fa[y];
 66         PushDown(y); PushDown(x);
 67         ch[y][!kind] = ch[x][kind];
 68         if(ch[x][kind]) fa[ch[x][kind]] = y;
 69         if(z) {
 70             if(y == ch[z][0]) ch[z][0] = x;
 71             else ch[z][1] = x;
 72         }
 73         fa[x] = z; fa[y] = x;
 74         ch[x][kind] = y;
 75         PushUp(y);
 76     }
 77
 78     void Splay(int x, int goal) {
 79         PushDown(x);
 80         while(fa[x] != goal) {
 81             int y = fa[x], z = fa[y];
 82             PushDown(z); PushDown(y); PushDown(x);
 83             int kind1 = x == ch[y][0];
 84             int kind2 = y == ch[z][0];
 85             if(z == goal) {
 86                 Rotate(x, kind1);
 87             } else {
 88                 if(kind1 == kind2) Rotate(y, kind1);
 89                 else Rotate(x, kind1);
 90                 Rotate(x, kind2);
 91             }
 92         }
 93         PushUp(x);
 94         if(!goal) root = x;
 95     }
 96
 97     void RTO(int k, int goal) {
 98         int x = root;
 99         PushDown(x);
100         while(sz[lson] + 1 != k) {
101             if(sz[lson] >= k) x = lson;
102             else k -= sz[lson] + 1, x = rson;
103             PushDown(x);
104         }
105         Splay(x, goal);
106     }
107
108     void Travel(int x) {
109         if(lson) Travel(lson);
110         printf("travel : %d\n", x);
111         if(rson) Travel(rson);
112         PushUp(x);
113     }
114
115     int Suf(int x) { // 找后继
116         if(rson) {
117             PushDown(x);
118             x = rson;
119             while(lson) {
120                 x = lson;
121                 PushDown(x);
122             }
123         }
124         return x;
125     }
126
127     int Query(int l, int r) {
128         Splay(r, 0); // 把原来节点的位置旋转到root位置
129         int ans = sz[ch[root][0]]; // 因为多了一个节点,所以不用+1
130         RTO(l, 0); // 把第l个数的前一个旋到root
131         Splay(Suf(r), root); // 把后继旋到ch[root][1]
132         rev[keytree] ^= 1; //区间翻转
133         return ans;
134     }
135
136 }spy;
137
138 bool cmp(const node &a, const node &b) {
139     if(a.val == b.val) return a.id < b.id;
140     return a.val < b.val;
141 }
142
143 int main() {
144     int n;
145     while(scanf("%d", &n), n) {
146         spy.n = n;
147         for(int i = 1; i <= n; i++) {
148             scanf("%d", &spy.num[i]);
149             a[i].id = i;
150             a[i].val = spy.num[i];
151         }
152         sort(a + 1, a + 1 + n, cmp);
153         spy.Init();
154         for(int i = 1; i <= n; i++) {
155             int ans;
156             ans = spy.Query(i, a[i].id);
157             if(i == n) printf("%d\n", ans);
158             else printf("%d ", ans);
159         }
160     }
161     return 0;
162 }
时间: 2024-10-13 05:40:52

HDU 1890:Robotic Sort(Splay)的相关文章

HDU 1890 Robotic Sort(splay)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=1890 [题意] 给定一个序列,每次将i..P[i]反转,然后输出P[i],P[i]定义为当前数字i的所在位置.相等的两个数排序后相对位置不变. [思路] 由于相对位置不变,所以可以根据数值与位置重编号. 依旧使用直接定位从上到下旋转至根的splay写法.每次将i结点旋转至根,则答案为左儿子大小+i,然后将i删掉合并左右儿子. 需要注意合并时判断左右儿子是否为空,以及各种pushdown下传标记.

HDU 1003:Max Sum(DP)

Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 142742    Accepted Submission(s): 33225 Problem Description Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max s

HDU 5775:Bubble Sort(树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=5775 Bubble Sort Problem Description P is a permutation of the integers from 1 to N(index starting from 1).Here is the code of Bubble Sort in C++. for(int i=1;i<=N;++i) for(int j=N,t;j>i;—j) if(P[j-1] > P

HDU 2767:Proving Equivalences(强连通)

http://acm.hdu.edu.cn/showproblem.php?pid=2767 题意:给出n个点m条边,问在m条边的基础上,最小再添加多少条边可以让图变成强连通.思路:强连通分量缩点后找入度为0和出度为0的点,因为在强连通图里面没有一个点的入度和出度都为0,所以取出度为0的点和入度为0的点中的最大值就是答案.(要特判强连通分量数为1的情况) 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostre

HDU 1051: Wooden Sticks(贪心)

Wooden Sticks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11244    Accepted Submission(s): 4627 Problem Description There is a pile of n wooden sticks. The length and weight of each stick a

HDU 5876:Sparse Graph(BFS)

http://acm.hdu.edu.cn/showproblem.php?pid=5876 Sparse Graph Problem Description In graph theory, the complement of a graph G is a graph H on the same vertices such that two distinct vertices of H are adjacent if and only if they are not adjacent in G

BZOJ 1588:营业额统计(Splay)

http://www.lydsy.com/JudgeOnline/problem.php?id=1588 题意:中文题意. 思路:每一个点每一个点插入Splay,然后插入新的一个点之后,查这个节点的前驱和后继,即左子树最右边的点和右子树最左边的点.然后再从两个点中取个差值较小的就是答案了.要注意Rotate的时候一些细节(要给 rt 的父亲的父亲更新其孩子的值),还有Splay的细节:如果 rt 和 父节点都是要旋转相同方向,应该先旋转父亲节点再旋 rt,如果旋转不同方向就都是旋 rt. 1 #

HDU 4825:Xor Sum(Trie)

http://acm.hdu.edu.cn/showproblem.php?pid=4825 题意:给出N个数,M个询问,每个询问给出一个X,问在这N个数中哪个数和X异或后结果最大. 思路:可以用Trie构造出sigmaSize为0和1的点,先将N个数插入Trie,然后询问在Trie上尽量找可以不同的数,不同的话异或起来是最大的. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #in

HDU 4763:Theme Section(KMP)

http://acm.hdu.edu.cn/showproblem.php?pid=4763 Theme Section Problem Description It's time for music! A lot of popular musicians are invited to join us in the music festival. Each of them will play one of their representative songs. To make the progr