小练习,splay区间反转
来源:互联网 发布:电路设计用什么软件 编辑:程序博客网 时间:2024/06/15 15:17
一道codevs的区间翻转问题。
http://codevs.cn/problem/1743/
题意,每次找最左边的数,令为k: k=1,结束; 否则,ans++,翻转[1,k].
(给定的是全排列,所以,加两个点就可以直接做了。)
题目中说可能无解,但我觉得应该有解,所以就没管-1. 求大神指导一下到底是否一定有解。
(当然最好定义一个较大的操作数,大于此操作数仍无法结束程序,输出-1)
以下简要分析:
①两个虚拟点是极有用的,有了这两个虚拟点就避免讨论l=1时l-1找不到的情况。
②(我用的指针)插入的时候,一直向最右边插就可以了(记得每次把插入的点旋到根)~~~PS:我傻逼了,splay如果旋完我直接return 了,忘记如果旋到根要变root的指向。
③指针的操作就是不容易直接记录每个点的位置(好像可以直接找)(管它的,我写复杂了~) 所以我还用了size存左子数个数,每次找排名第2的(有虚拟节点),把它的值找到,是1结束,否则翻转。
其实我这样看似多余,实则是有必要的---- 你每次直接调用地址进行操作,它上面可能有lazy标记没有变化,那么你操作完就有可能偏离了正常的答案,因此就需要从上往下依次找,每层下放lazy.
④pushdown是在每次往下查询的时候都要用到的,只要需要从根往下找,每层pushdown以下,操作类似于线段树。
之后就是常规的splay就可以了。
#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#define maxn 300000+20using namespace std;int n;int cnt=0;struct node{node *f;node *ch[2];int key;int lazy;int size;}S[maxn];node *root;void pushup(node *u){u->size=1;if(u->ch[0])u->size+=u->ch[0]->size;if(u->ch[1])u->size+=u->ch[1]->size;}void pushdown(node *u){if(u==NULL||!u->lazy)return ;if(u->ch[0])u->ch[0]->lazy^=1;if(u->ch[1])u->ch[1]->lazy^=1;node *y;y=u->ch[0];u->ch[0]=u->ch[1];u->ch[1]=y;u->lazy=0;}void rotate(node *u){node *f=u->f;if(f==NULL)return ;pushdown(u);pushdown(f);node *ff=f->f;int d=u==f->ch[1];int dd=0;if(ff!=NULL)dd=f==ff->ch[1];if(u->ch[d^1])u->ch[d^1]->f=f;f->ch[d]=u->ch[d^1];f->f=u;u->ch[d^1]=f;if(ff!=NULL)ff->ch[dd]=u;u->f=ff;pushup(f);pushup(u);}void splay(node *u,node *p){pushdown(u);while(u->f!=p){node *f=u->f;node *ff=f->f;if(ff==p){rotate(u);break;}int d=u==f->ch[1];int dd=f==ff->ch[1];if(d==dd)rotate(f);else rotate(u);rotate(u);}if(p==NULL)root=u;pushup(u);}void insert(int key){if(root==NULL){root=&S[++cnt];root->lazy=0;root->key=key;root->size=1;root->ch[0]=root->ch[1]=root->f=NULL;return ;}node *u=root;node *y;while(1){u->size++;/*if(key<u->key){if(u->ch[0])u=u->ch[0];else{y=&S[++cnt];y->lazy=0;y->ch[0]=y->ch[1]=NULL;y->size=1;y->key=key;y->f=u;u->ch[0]=y;break;}}else{*/if(u->ch[1])u=u->ch[1];else{y=&S[++cnt];y->lazy=0;y->ch[0]=y->ch[1]=NULL;y->key=key;y->size=1;y->f=u;u->ch[1]=y;break;}}splay(y,NULL);}node * find(int k){node *u=root;while(1){pushdown(u);int size=1;if(u->ch[0])size+=u->ch[0]->size;if(size==k)return u;if(k<size)u=u->ch[0];else {k-=size;u=u->ch[1];}}}int find2(){return find(2)->key;}void flip(int l,int r){//l,r+2node *ll=find(l);node *rr=find(r+2);splay(ll,NULL);splay(rr,root);root->ch[1]->ch[0]->lazy^=1;}void dfs(node *u){if(u->ch[0])dfs(u->ch[0]);printf("%d ",u->key);if(u->ch[1])dfs(u->ch[1]);}int main(){scanf("%d",&n);root=NULL;int x;insert(0);for(int i=1;i<=n;i++){scanf("%d",&x);insert(x);}insert(n+1);int ans=0;while(1){int k=find2();if(k==1)break;ans++;flip(1,k);}printf("%d\n",ans);return 0;}
1 0
- 小练习,splay区间反转
- Splay 区间反转
- 【BZOJ3223】文艺平衡树,Splay反转区间
- codevs 1743 反转卡片【Splay区间翻转】
- POJ 3667 splay区间合并练习
- hdu1890 Robotic Sort Splay树,区间反转,lazy标记
- POJ 3580 SuperMemo(splay成段更新、区间最小值、反转、插入和删除、区间搬移)
- 最大值(最基本splay区间修改,注意小细节)
- 【Splay练习】
- splay练习
- Core Java小练习 - 反转文字
- HDU 3487 Play with Chain (Splay tree)区间切割和反转操作。
- splay区间操作
- Splay维护区间
- Splay 区间维护模板
- HDU1754 Splay 区间维护
- Splay区间修改
- 【POJ3468】区间操作 Splay
- I2S 和 PCM 区别
- 在ImageButton上添加文字
- 仿哔哩哔哩应用客户端Android版源码
- Space+onTouchEvent=Hitarea:像Flash那样在Android中扩大点击区域
- Android 的通用权限
- 小练习,splay区间反转
- 完全个性化ListView的一个实现思路(太新手向了)
- jsp中生成验证码,不用session也可以(主要是:思想)
- java框架模式_低耦合高内聚法则
- EditText与WebView焦点冲突
- React Native Mac配置指南
- redis 客户端连接
- sui-mobile框架入门一
- LeetCode 226 Invert Binary Tree