zoj_2243笛卡尔树的构造,开始被topcoder上的教程吸引去看这题。题目中说这种数据结构叫treap然后就按照treap的insert加上左旋右旋去做了,结果果断TLE。然后网上找了一下关于笛卡尔树的资料,发现了一些问题的端倪。
首先,treap和笛卡尔树从形式上来说是完全一样的,即是一颗二叉搜索树和二叉堆的结合(不是严格意义上的二叉堆,因为二叉堆是一颗完全二叉树,而treap不是)。但是他们的目的也许不太一样。treap更大的意义在于为了维持BST的平衡型而找到的一种随即化构造的方案。在treap中,insert的时候节点的value值是随机生成的。因此在逐个insert节点的时候能够保证treap的统计意义上的平衡。然而,笛卡尔树的目的更多是为了rmq问题和LCA问题的转化。
其次,我们可以看到,在zoj_2243中,如果使用treap,按照题意一个个插如节点,随即化就被打破了,judge系统的数据也许不随机,从而导致treap的链化,弱化了平衡性,理想的NlogN的复杂度,可能退化到N^2,导致最后的TLE(可能左旋右旋操作的消耗也对应能有所影响).
最后,找到了一种排序之后直接构造笛卡尔树的方法。首先将节点序列按照key从小到大排序,然后按照顺序插入节点,注意到排序之后,插入的节点的key值一定是树中最大的,所以只需查找最右端的路径,找到一个节点A[i]的value大于待插入节点的value,同时A[i]->right的value小于待插入节点的value。找到之后,只需将A[i]的right指向待插入的节点,A[i]的right原来指向的节点赋值给待插入节点的left指针。注意到查找最右路径的方向,如果从下到上查找,复杂度比较容易分析O(N)(因为查找过的节点必然会旋转到某个节点的左子节点,因此每个查找过的节点只会被查找一次),如果从上倒下,比较复杂(和最右端的最终的路径长度有关吧),会超过N,甚至更高,可能为O(N^2)。
另外,找到一种使用排序加左旋的方法,就是一样先排序,然后使用treap插入节点,可以发现,所有的旋转都为左旋。这种方法也TLE了,这种方法有一个很重要的意义,就是分析了上个方法中从上到下扫描的复杂度。因为这两种方法的效率是等价的,都TLE。
最后,同样的题ZOJ是5M的,POJ是2M的,我用了从上到下2.5S,从下到上0.6S。
代码zoj_2243
#include<iostream> #include<cstdio> #include<string> #include<string.h> #include<algorithm> using namespace std; class treap_node { public: string label; int p; treap_node* left; treap_node* right; treap_node() { left=NULL; right=NULL; } }; class treap { public: treap_node*root; treap() { root=NULL; } void treap_left_rotate(treap_node*&a) { treap_node*b=a->right; a->right=b->left; b->left=a; a=b; } void treap_right_rotate(treap_node*&a) { treap_node*b=a->left; a->left=b->right; b->right=a; a=b; } void treap_insert(treap_node*&a,string label,int p) { if(!a) { a=new treap_node; a->label=label; a->p=p; } else if(label<a->label) { treap_insert(a->left,label,p); if(a->left->p>a->p) treap_right_rotate(a); } else { treap_insert(a->right,label,p); if(a->right->p>a->p) treap_left_rotate(a); } } void plist(treap_node*a) { if(a!=NULL) { cout<<"("; plist(a->left); cout<<a->label<<"/"<<a->p; plist(a->right); cout<<")"; } } }; int num; treap_node n[50001]; bool cmp(const treap_node&n1,const treap_node&n2) { return n1.label<n2.label; } void insertN(treap_node*&p) { for(int i=0;i<num;i++) { treap_node* pre=NULL; treap_node* tmp=p; while(tmp!=NULL&&tmp->p>n[i].p) { pre=tmp; tmp=tmp->right; } if(pre==NULL) { treap_node* node=new treap_node; node->label=n[i].label; node->p=n[i].p; p=node; p->left=tmp; } else { treap_node* node=new treap_node; node->label=n[i].label; node->p=n[i].p; pre->right=node; node->left=tmp; } } return; } int main() { freopen("e:\\zoj\\zoj_2243.txt","r",stdin); while(cin>>num&&num) { treap* p=new treap; getchar(); for(int i=0;i<num;i++) { char c[1000]; int pi; scanf("%[^/]s",c); scanf("/%d",&pi); getchar(); string str; str.append(c); treap_node node; node.label=str; node.p=pi; n[i]=node; //p->treap_insert(p->root,str,pi); } sort(n,n+num,cmp); //for(int i=0;i<num;i++) // p->treap_insert(p->root,n[i].label,n[i].p); insertN(p->root); p->plist(p->root); cout<<endl; } return 0; }
发表评论
-
图的割点tarjan---zoj_1119
2011-10-24 23:00 1228http://acm.zju.edu.cn/on ... -
大数计算模板---zoj_3447
2011-10-24 16:47 945http://acm.zju.edu.cn ... -
BFS与双向BFS---zoj_1505
2011-10-09 17:14 1639http://acm.zju.edu.c ... -
静态treap+线段树---zoj_2112
2011-09-29 23:06 1706http://acm.zju.edu ... -
NIM博弈游戏,SG函数---zoj_3084,zoj_2083
2011-09-23 23:00 1313Nim游戏是两个人进行的游戏有如下规则: ... -
struct数据对齐与#pragma pack(n)
2011-09-14 16:38 1097对struct数据对齐与#pragma pac ... -
多重背包--zoj_2156
2011-09-14 11:10 859首先介绍经典的三种背包问题,0-1背包,完全 ... -
模式串匹配---KMP
2011-08-31 20:49 1275朴素的的模式串匹配算法通常要在向前移动文本指针 ... -
八数码问题(A*&&双向BFS)---zoj_1217
2011-08-30 22:13 1663题目地址:http://acm.zju.edu.cn/onli ... -
ac自动机以及它上面的DFA
2011-08-08 23:04 2475AC自动机(Aho-Corasick)主要用 ... -
二分图最大匹配(匈牙利算法)--zoj1516,1525,2223
2011-07-20 22:36 1182二分图G(E,V)将点集合V分成两个部分L,R ... -
网络最大流(EK)---zoj_1734
2011-07-19 16:34 2127网络最大流是图论中的一个典型问题,为了精确的定 ... -
trie和前缀检查---zoj_2876
2011-07-13 23:03 864trie树是一种多叉树,广泛用于字典检索。如 ... -
位图bitmap
2011-07-13 21:08 911bitmap是一种广泛使用的数据结构,主要用在 ... -
LAC和RMQ的转化---zoj_3195
2011-07-12 22:35 1071我擦。。纠结了好久啊,从SF到TLE,先总结2 ... -
LAC的tarjan(离线)算法---zoj_1141
2011-07-08 17:52 1654LCA就不解释了,这里主要再次复习一下LC ... -
中缀表达式的转化---zoj_2483,zoj_3025
2011-07-04 18:54 1139在我们的日常生活中,中缀表达式是最常用的计算表达方式 ... -
STL---priority_queue zoj_2212,zoj_2724,zoj_3230
2011-06-28 17:50 1261priority_queue顾名思意是优先 ... -
STL---sort
2011-06-25 16:39 805引用:http://blog.csdn.net/rattl ... -
线段染色,矩形切割,离散化---zoj_2301,zoj_1128
2011-06-24 22:32 1361染色问题:在一维坐标轴上(最右端为M),有N ...
相关推荐
基环树 笛卡尔树--2021.09.06(E).pdf
机器人仿真,画出机械臂在笛卡尔空间的运动轨迹
详细的数据结构延伸介绍(包括AC自动机SBT,伸展树,字典树,并查集,笛卡尔树,二叉堆,斐波那契堆,哈希表,红黑树,后缀树,后缀数组,树状数组,线段树,左偏树,斜堆),自己整理和归纳相当长的时间,里面有网上的资料,牛人的...
笛卡尔转极坐标
螺线的笛卡尔坐标系方程为: 螺线从笛卡尔坐标转为极坐标方程为: 阿基米德螺线在极坐标系下极径r和极角theta为线性关系,方程为: 计算步骤如下: 1.通常我们首先得到螺线在笛卡尔坐标下的一些点x,y。 2...
html的笛卡尔积爱心代码 是3D旋转的哟 拿回去show给喜欢的人看吧
笛卡尔坐标系,大地坐标系,站心地平坐标系(线型和极坐标形式)之间的转换源代码
C#,笛卡尔树(Cartesian Tree)的构造、遍历算法与源代码 笛卡尔树是一种特定的二叉树数据结构,可由数列构造, 在范围最值查询、范围top k查询(range top k queries)等问题上有广泛应用。勒内·笛卡尔(René ...
肺超声视频中的B线检测笛卡尔与极坐标表示_B-line Detection in Lung Ultrasound Videos Cartesian vs Polar Representation.pdf
本程序实现在不同的笛卡尔坐标系统中旋转变换。
笛卡尔心形线-少儿编程scratch项目源代码文件案例素材.zip
可以实现从笛卡尔坐标系到大地坐标系的转换功能 超级实用 推荐使用
shapely是基于笛卡尔坐标的几何对象操作和分析Python库。底层基于GEOS和JTS库。shapely无法读取和写数据文件,但可以基于应用广泛的一些格式和协议进行序列化(serialize)和去序列化(deserialize)操作。而且shapely不...
详细介绍了各种坐标系统转换运算,由笛卡尔坐标转换为大地坐标; 由大地坐标转换为笛卡尔坐标;由笛卡尔坐标转换为站心地平坐标;由站心地平直角坐标转换为站心地平极坐标
笛卡尔定理推导
GPS数据处理中为了满足不同的需要,处理的数据要进行坐标转换,得到在不同坐标系统下的结果,下面是笛卡尔坐标系,大地坐标系,站心地平坐标系(线型和极坐标形式)之间的转换源代码
笛卡尔树(CartesianBinTree) RandomMergeBinTree(RandomMergeBinTree) 展开树(SplayTree) 其他订单集合: 跳过清单(SkipList) 和别的... 基于AVL和Splay树的堆(AvlSplayHeap) 基于AVL树的堆并通过创建节点...
雷达数据转成MDV格式,便于在笛卡尔坐标中显示
资源名:基于MATLAB实现了极坐标下的傅里叶变换,对一个给定 n×n 的二维信号,其计算复杂度等价于笛卡尔坐标下的2D-FFT 资源类型:matlab项目全套源码 源码说明: 全部项目源码都是经过测试校正后百分百成功运行的...
有限差分法求解三位笛卡尔坐标系下薛定谔方程,可以根据精度需求调节二阶导数算符计算精度(四阶拉格朗日插值法误差余项可到o(h^6))