2013 多校第九场 hdu 4699 Editor(vector OR splay tree)
来源:互联网 发布:智能网络液晶电视 编辑:程序博客网 时间:2024/06/16 00:17
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4699
题目大意:一个文件编译器,有一个指针,五种操作:(1)在指针前面插入一个数(2)把指针前的数删除(3)指针往左移一位(4)指针往右移一位(5)询问前k个数的最大前缀和(其中 k <= n),n 为指针位置,并输出。
思路:以指针为分界线,分别建两个栈,前面为 a,后面为b,由于k<=n,那么对于a 再维护两个值s和s_max,由于b中的元素会加到 a 的栈顶,那么还要在 b 中记录一个 val 值。由于要询问 k ,那么用vector模拟就行了。
I x a.push(x)
D a.pop()
L a.push(b.pop())
R b.push(a.pop())
Q k a[k].s_max
概括起来就是上面这几句。比赛的时候,想太多,我们当时想到链表,天真的以为插入、删除一个数,还要去更新后面的 s和s_max,其实不用,因为 k<=n,只要跟着指针的移动走就好了。。 SB 了,挫啊。。
赛后又问了下别人,他们说他们是用伸展树做的,哎,表示没学过伸展树,后来一看,由于操作简单,这样简单维护下就可以了。。无语。。
没办法,不会就要学,昨天看了一天伸展树,今天过来敲这道题目,调试老半天,调完过样例,来了一发,TLE了。。 由于我之前的L、R都是直接将数旋转的,让树根为指针所在位置,Q的时候,一遍找下去,可能这样比较耗时,后来,拿了 pos 来记录位置,询问时直接旋转k大的数,然后输出,过了样例,一交,发现是 WA,找了老半天错误,然后TLE了。。终于在各种小地方的优化下,以 1968ms 的微弱优势成功AC,虽然时间有点那个啥,但还是兴奋啊,毕竟写了两天了啊,从WA到TLE再到AC。。T^T
总结一下自己犯的各种SB错误:(1)第一遍写,我的 s 表示的是所有前面的和(不是以它为跟的子树),然后又搞了个延时标记,插入删除时对右儿子放一个,然后 s_max 表示的是左边的 s 最大值,上传时只上传 size 。先不说这个s,这个 s_max 就有问题,当前节点的 s_max 是不能由它的左子树过来的(在我这种SB定义下),会小,因为它左儿子可能还有右儿子,也就是说它和它的左儿子不是挨着的。貌似延时标记这样处理这个 s 是对的(当然也只是我个人想想,还缺乏验证)。。(2)感觉到这个 s 有问题,因为我感觉一个节点的每个值,都是相对于以它为根节点的子树来说的,然后我就删掉了这个延时标记,因为这样插入、删除旋转后只影响到树根的维护的值的变化,然后在 push_up(maintain)这里加了 s 和 s_max,然后由于是定义全都换成以它为根的子树了,那么 s_max 也变了,但是第一遍写的时候,还是有一个地方写错了,我写的是 max( ch[ 0 ]->s_max , ch[ 0 ]->s +v ,ch[ 1 ]->s_max ),这里就是一直没发现,今天吃完午饭,然后造随机数据才发现的。。 = = ,ch[ 1 ]->s_max 应该改为 ch[ 1 ]->s_max + v + ch[ 0 ]->s,因为是前缀和,明显要把左子树的和给拿过来嘛,SB了。。 这样改了之后,又交,发现TLE,就感觉别人写的 splay 能过,我的应该也差不多,我把上面求 max 那个分 if 讨论(其实我换 null 的原因就是省的 if 讨论。。囧),这样可能会省一点时间,发现还是TLE,最后我把 init 里的 null 初始化放在 while 外面去了,终于以微弱的领先优势绝杀了。。。 = = (3)改的时候,其实最麻烦的是处理我加上去的那个虚拟节点(因为split 限制 left 不为空),它的 s = 0,s_max = -INF(不能影响到它的父亲结点取s_max),它的左儿子是 null,maintain 的时候要单独考虑,因为null 的 s 为0,不然它的 s_max 就变为0了!
好了,以上纯属我个人娱乐,如果占用大家宝贵时间,实在抱歉。。 = =
哎,看了大家过的时间,Splay应该不至于超时,不知道哪里写搓了。。 希望各路神牛路过的时候能指教一下。。
把两份代码先都贴上来吧。。
栈模拟代码如下:
#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;const int INF = 0x0fffffff ;struct Node{ int s,s_max; int val; Node(){} Node(int a,int b,int c) : s(a),s_max(b),val(c) {}};vector <Node> a,b;char str[11];int main(){ int q; while(~scanf("%d",&q)) { a.clear(); b.clear(); a.push_back(Node(0,-INF,0)); int x; while(q--) { scanf("%s",str); if(str[0] == 'I') { scanf("%d",&x); int size = a.size(); a.push_back(Node(a.back().s + x,max(a.back().s_max,a.back().s + x),x)); } else if(str[0] == 'D') { if(a.size()>1) { a.pop_back(); } } else if(str[0] == 'L') { if(a.size()>1) { int val = a.back().val; a.pop_back(); b.push_back(Node(0,0,val)); } } else if(str[0] == 'R') { if(b.size()>=1) { int val = b.back().val; b.pop_back(); a.push_back(Node(a.back().s + val,max(a.back().s_max,a.back().s + val),val)); } } else { scanf("%d",&x); printf("%d\n",a[x].s_max); } } } return 0;}
伸展树代码如下(1968ms,汗):
#pragma comment(linker, "/STACK:10240000000000,10240000000000")#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int INF = 0x0fffffff ;struct Node{ Node* ch[2]; int flag; int v; int s_max,s; int size ; Node(){} Node(int v,int flag,Node* null): v(v),flag(flag) { ch[0] = ch[1] = null;s = 0;s_max = 0;size = 1;} int cmp(int x) { if(ch[0]->size+1 == x) return -1; else return x < ch[0]->size+1 ? 0 : 1; } void maintain(Node* null) { if(flag == 1 && ch[1] == null) { size = 1; s = 0; s_max = -INF; return ; } size = 1; size += ch[0]->size + ch[1]->size ; s = v; if(ch[0] != null) { s += ch[0]->s; s_max = max(ch[0]->s_max,ch[0]->s + v); if(ch[1] != null) { s += ch[1]->s; s_max = max(s_max,ch[0]->s + v + ch[1]->s_max); } } else { s_max = v; if(ch[1] != null) { s += ch[1]->s; s_max = max(v,v + ch[1]->s_max); } } }};struct Splay{ Node *root,*null; int n,pos; void init() { null = new Node; null->ch[0] = null->ch[1] = null; null->v = 0; null->size = 0; null->s_max = 0; null->s = 0; } void build() { root = new Node(0,1,null); root->s_max = -INF; n = pos = 1; } void rotate(Node* &o,int d) { Node* k = o->ch[d^1];o->ch[d^1] = k->ch[d];k->ch[d] = o; o->maintain(null);k->maintain(null);o = k; } void splay(Node* &o,int k) { int d = o->cmp(k); if(d == 1) k -= o->ch[0]->size + 1; if(d != -1) { Node* p = o->ch[d]; int d2 = p->cmp(k); if(d2 != -1) { int k2 = d2==0? k: k - p->ch[0]->size - 1; splay(p->ch[d2],k2); if(d == d2) rotate(o,d^1); else rotate(o->ch[d],d); } rotate(o,d^1); } } void split(Node* o,int k,Node* &left,Node* &right) { splay(o,k); left = o; right = o->ch[1]; o->ch[1] = null; left->maintain(null); } Node* merge(Node* left,Node* right) { splay(left,left->size); left->ch[1] = right; left->maintain(null); return left; } void solve(char str[]) { int x; if(str[0] == 'I') { n++; scanf("%d",&x); Node *mid = new Node(x,0,null); Node *left,*right,*o; split(root,pos,left,right); root = merge(merge(left,mid),right); pos++; } else if(str[0] == 'Q') { scanf("%d",&x); splay(root,x+1); //debug(root); printf("%d\n",max(root->ch[0]->s_max,root->ch[0]->s + root->v)); } else if(str[0] == 'L') { if(pos >= 2) pos--; } else if(str[0] == 'R') { if(pos < n) pos++; } else if(pos>1 && str[0] == 'D') { n--; Node *mid,*left,*right,*o; split(root,pos - 1,left,o); split(o,1,mid,right); root = merge(left,right); pos--; } //puts("last"); //debug(root); } void debug(Node* o) { if(o == null) { puts("(null)"); return ; } printf("%d|%d|%d(",o->v,o->s_max,o->s); if(o->ch[0]!=null) printf("%d|%d|%d,",o->ch[0]->v,o->ch[0]->s_max,o->ch[0]->s); else printf("null,"); if(o->ch[1]!=null) printf("%d|%d|%d",o->ch[1]->v,o->ch[1]->s_max,o->ch[1]->s); else printf("null"); puts(")"); if(o->ch[0]!=null) debug(o->ch[0]); if(o->ch[1]!=null) debug(o->ch[1]); }} sp;char str[11];int main(){ //reopen("D://in.txt","r",stdin);//freopen("D://out1.txt","w",stdout);sp.init(); int n; while(~scanf("%d",&n)) { sp.build(); while(n--) { scanf("%s",str); sp.solve(str); } } return 0;}/*11I -5I -3I 9I -3Q 4*/
- ubuntu下安装配置SSH
- 章小结
- 打印100以内的素数
- Window.open() 全攻略
- VC2010中编译Sqlite3为静态库并带加密功能的方法
- 2013 多校第九场 hdu 4699 Editor(vector OR splay tree)
- 多态的优势与特点,为什么用多态
- Delegate如何进行类型转换?
- 【讲解各种手机所有内存卡知识】
- Unix 环境高级编程学习笔记(一)
- 【原创分享】嵌入式linux应用之内核移植定制篇-后篇(修复部分问题)(linux-3.8.12 mini2440)
- 备份所有短信
- 输入一个整数n,求从1 到n 这n 个整数的十进制表示中1 出现的次数)
- Java中的各访问修饰符权限