HDU1890 Robotic Sort(Splay)
2016-03-10 17:50
197 查看
有一个长度为n(1≤n≤105)n(1 \leq n \leq 10^5)的排列,排列中的每个元素pi(1≤pi≤n)pi(1 \leq pi \leq n)。每次操作翻转第i个元素和第i大元素之间所有的数,并且输出第i大元素的位置。
刚开始看见又是区间翻转又是求第k大就晕了- -,网上搜了搜题解+自己理会发现:用原数组的下标来建树,每次把排序后的第i个元素对应的原数组的下标旋转到根,i+sz[ch[root][lson]]i+sz[ch[root][lson]]就是我们要的结果,然后把根删掉,对i+1进行操作。
为什么呢?通过手推小数据不难发现,每次把第i个数和第i大的数翻转之后,第i大的数被移动到了第i个位置,而且左边i个数是不下降排列,也就是说,每次翻转之后,第i个数就不会再被翻转,它也就没用了,所以可以删掉。
结果,当我用原先的splay模板写了之后发现TLE,坑爹!于是乎,构造了一个小数据debug,觉得是伸展中的pushdown位置没有写对,因为之前都没碰见过直接在伸展函数中写pushdown,好吧,这才过了- -
刚开始看见又是区间翻转又是求第k大就晕了- -,网上搜了搜题解+自己理会发现:用原数组的下标来建树,每次把排序后的第i个元素对应的原数组的下标旋转到根,i+sz[ch[root][lson]]i+sz[ch[root][lson]]就是我们要的结果,然后把根删掉,对i+1进行操作。
为什么呢?通过手推小数据不难发现,每次把第i个数和第i大的数翻转之后,第i大的数被移动到了第i个位置,而且左边i个数是不下降排列,也就是说,每次翻转之后,第i个数就不会再被翻转,它也就没用了,所以可以删掉。
结果,当我用原先的splay模板写了之后发现TLE,坑爹!于是乎,构造了一个小数据debug,觉得是伸展中的pushdown位置没有写对,因为之前都没碰见过直接在伸展函数中写pushdown,好吧,这才过了- -
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #define MAXN 100010 using namespace std; int n,root,rev[MAXN],sz[MAXN],ch[MAXN][2],fa[MAXN]; inline void Swap(int &a,int &b) { int c = a; a = b; b = c; } void pushup(int x) { sz[x] = sz[ch[x][0]]+sz[ch[x][1]]+1; } void pushdown(int x) { if(rev[x]) { rev[ch[x][0]] ^= 1; rev[ch[x][1]] ^= 1; swap(ch[x][0],ch[x][1]); rev[x] = 0; } } void rotate(int x) { int y = fa[x],z = fa[y],f = (ch[y][1]==x); ch[y][f] = ch[x][!f]; if(ch[y][f]) fa[ch[y][f]] = y; ch[x][!f] = y,fa[y] = x; fa[x] = z; if(z) ch[z][ch[z][1]==y] = x; pushup(y); } void splay(int x,int goal) { int y,z; pushdown(x); while(fa[x] != goal)//坑爹的pushdown,貌似还要注意顺序 { y = fa[x],z = fa[y]; if(z == goal) { pushdown(y); pushdown(x); rotate(x); } else { pushdown(z); pushdown(y); pushdown(x); if((ch[z][0]==y) == (ch[y][0]==x)) rotate(y); else rotate(x); } } if(goal == 0) root = x; pushup(x); } void New(int &x,int val) { x = val; sz[x] = 1; } void build_tree(int &x,int L,int R,int F)//按照原数组下标建树 { int mid = (L+R)/2; New(x,mid); fa[x] = F; if(L == R) return; if(L < mid) build_tree(ch[x][0],L,mid-1,x); if(R > mid) build_tree(ch[x][1],mid+1,R,x); pushup(x); } int nxt(int x) { pushdown(x); while(ch[x][1]) { x = ch[x][1]; pushdown(x); } return x; } void del_root() { if(ch[root][0] == 0) { root = ch[root][1]; fa[root] = 0; } else { int x = nxt(ch[root][0]); splay(x,root); ch[x][1] = ch[root][1]; fa[ch[root][1]] = x; root = x; fa[root] = 0; pushup(root); } } struct A { int num,id; bool operator <(const A &b) const { if(num == b.num) return id < b.id; else return num < b.num; } }a[MAXN]; void Init() { root = 0; memset(sz,0,sizeof sz); memset(fa,0,sizeof fa); memset(rev,0,sizeof rev); memset(ch,0,sizeof ch); for(int i = 1; i <= n; i++) { scanf("%d",&a[i].num); a[i].id = i; } sort(a+1,a+n+1); build_tree(root,1,n,0); } int main() { while(scanf("%d",&n) != EOF&&n) { Init(); for(int i = 1; i < n; i++) { splay(a[i].id,0); rev[ch[root][0]] ^= 1; printf("%d ",i+sz[ch[root][0]]); del_root(); } printf("%d\n",n); } }
相关文章推荐
- 利用redrat模拟遥控器
- linux修改用户打开文件数量的限制
- 如何判断微信内置浏览器
- Codeforces Round #344 (Div. 2) A. Interview
- 网页自动跳转/定时跳转代码
- Spark的39个机器学习库-英文
- leetcode(198)(213) HouseRobber HouseRobber-II
- 利用ViewPager实现引导界面+底部小圆点
- java 正则表达式
- 安卓sdk FaceDetector 进行人脸抓取
- javascript精华技巧
- C# 游戏开发中使用 Dictionary 实现消息分发
- window覆盖导航栏
- 条件注释
- jenkins配置svn、gradle、ssh
- myeclipse内存配置
- httpclient 学习备忘
- Android:常用代码片段整理
- iOS ViewController的生命周期分析和使用
- java设计模式——代理模式