题意:给定n个(label,priority)的二元组,以此构建笛卡尔树。所谓笛卡尔树,看label为二叉排序树,而看priority为堆。
思路:
方法1:(http://www.cnblogs.com/rainydays/archive/2011/06/15/2081266.html)先把节点按lable排序,从小到大依次插入,这样每次插入的节点就要插到排序二叉树的最右边。之前先建立一个priority最大的节点(不建立这个节点就会TLE,不清楚是写的不对还是什么原因,待查)。然后首先要找到最右儿子,然后向上找到第一个大于当前priority的节点。然后分两种情况,最右节点的priority和当前插入节点的priority比较,若大于则直接将当前插入节点接到其右子树。否则让当前插入节点取代最右节点位置并将原最右节点及其子树接到当前插入节点的左子树。
方法2:用RMQ来处理,还是首先要排序,每次递归处理一个区间,找出有最大第二关键字的那个做根。他左边的就是他的左子树,右边的是右子树。
时间复杂度方面,因为都需要排序故二者都是nlogn级别。但就构造笛卡尔树来说,方法一的摊还复杂度为O(n):使用数据结构栈,栈中保存的始终是右链,即根结点、根结点的右儿子、根结点的右儿子的右儿子……组成的链(这与结点中增加一个fa域是同样的作用),并且栈中从栈顶到栈底key依次减小。如果按照从后到前的顺序判断一个元素是否大于A[i],则每次插入的时间复杂度为O(k+1),k为本次插入中移除的右链元素个数。因为每个元素最多进出右链各一次,所以整个过程的时间复杂度为O(n)。而RMQ的初始化仍为nlogn。
其中读入灵活用scanf比较方便。具体内容:%*[ ],表示越过[ ]中的字符,%[a-z]表示读入字符串,直到遇到不是a-z中的字符为止。%[^a]表示读入字符串直到遇到字符a为止,但a并没有被读入。
方法1:
#include <stdio.h> #include <string.h> #include <stdlib.h> #define N 50005 struct node{ char str[100]; int left,right,fa,num; }tree[N]; int n; int cmp(const void* a,const void* b){ return strcmp((*(struct node*)a).str , (*(struct node*)b).str); } void dfs(int x){ if(!x) return; printf("("); dfs(tree[x].left); printf("%s/%d",tree[x].str,tree[x].num); dfs(tree[x].right); printf(")"); } int main(){ while(scanf("%d",&n) && n){ int i,j; tree[0].num = 0x3fffffff; for(i = 1;i<=n;i++) scanf("%*[ ]%[^/]/%d",tree[i].str,&tree[i].num); qsort(tree+1,n,sizeof(struct node),cmp); for(i = 0;i<=n;i++) tree[i].left = tree[i].right = tree[i].fa = 0; for(i = 1;i<=n;i++){ j = i-1; while(tree[j].num < tree[i].num) j = tree[j].fa; tree[i].fa = j; tree[tree[j].right].fa = i; tree[i].left = tree[j].right; tree[j].right = i; } dfs(tree[0].right); printf("\n"); } return 0; }
#include <stdio.h> #include <string.h> #include <stdlib.h> #define N 50005 struct node{ char str[100]; int left,right,fa,num; }tree[N]; int n,root; int cmp(const void* a,const void* b){ return strcmp((*(struct node*)a).str , (*(struct node*)b).str); } void dfs(int x){ printf("("); if(tree[x].left!=-1) dfs(tree[x].left); printf("%s/%d",tree[x].str,tree[x].num); if(tree[x].right!=-1) dfs(tree[x].right); printf(")"); } int main(){ while(scanf("%d",&n) && n){ int i,j,tmp; for(i = 0;i<n;i++) scanf("%*[ ]%[^/]/%d",tree[i].str,&tree[i].num); qsort(tree,n,sizeof(struct node),cmp); for(i = 0;i<n;i++) tree[i].left = tree[i].right = tree[i].fa = -1; root = 0; for(i = 1;i<n;i++){ j = root; while(tree[i].num < tree[j].num && tree[j].right!=-1) j = tree[j].right; if(tree[i].num < tree[j].num){ tree[j].right = i; tree[i].fa = j; }else if(j == root){ tree[j].fa = i; tree[i].left = j; root = i; }else{ tmp = tree[j].fa; tree[tmp].right = i; tree[i].fa = tmp; tree[j].fa = i; tree[i].left = j; } } dfs(root); printf("\n"); } return 0; }
方法2:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #define N 50005 struct node{ char str[100]; int w; }p[N]; int n,dp[N][20]; int cmp(const void* a,const void* b){ return strcmp((*(struct node*)a).str,(*(struct node*)b).str); } void st(){ int i,j,k = log((double)n+1)/log(2.); for(i = 1;i<=n;i++) dp[i][0] = i; for(j = 1;j<=k;j++) for(i = 1;i+(1<<j)-1<=n;i++){ if(p[dp[i][j-1]].w > p[dp[i+(1<<(j-1))][j-1]].w) dp[i][j] = dp[i][j-1]; else dp[i][j] = dp[i+(1<<(j-1))][j-1]; } } int query(int a,int b){ int k = log((double)(b-a+1))/log(2.); if(p[dp[a][k]].w > p[dp[b-(1<<k)+1][k]].w) return dp[a][k]; return dp[b-(1<<k)+1][k]; } void treap(int a,int b){ int k; if(a>b) return; k = query(a,b); printf("("); treap(a,k-1); printf("%s/%d",p[k].str,p[k].w); treap(k+1,b); printf(")"); } int main(){ while (scanf("%d",&n) && n) { int i; for(i = 1;i<=n;i++) scanf("%*[ ]%[^/]/%d",p[i].str,&p[i].w); qsort(p+1,n,sizeof(struct node),cmp); st(); treap(1,n); printf("\n"); } return 0; }