题意:给出n个点的键值与优先级,然后构建一棵笛卡尔树(中序遍历键值从小到大,且优先级满足最小堆的性质,即父节点的优先级一定比它左右孩子的优先级小)
题解:一开始憨厚地去写了一棵Treap,结果TLE,这时才分析,复杂度最坏情况下达到了n^2 = =!于是,先将结点按照键值从小到大排序,这样保证每次插入的结点都在最右端,考察根节点到最右端的那条链,优先级一定是从小到大递增的,而插入的新节点的位置应该位于第一个比它小的那个优先级的右孩子的位置,为了保持排序树的特性,还需要将那个结点原来的右孩子放到新插入结点的左孩子位置,这样操作之后,还是满足笛卡尔树的各种性质。
然后,考虑到一个结点若是被转到了另一个结点的左孩子位置,他就不可能在根到最右孩子的那条链上了,就不用考虑它了,其次,找第一个比要插入节点优先级小的结点是从最右孩子开始向根扩展的,实际上,这就是一个栈,栈顶为最右端的元素,整个栈形成一条到根节点的链,且一旦一个结点被退栈,他就再也不可能入栈了!于是,只需维护这个栈,nlogn排序,n的搜索就可以搞定了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 using namespace std; 6 const int N=50005; 7 struct Treap_Node 8 { 9 int left,right; 10 int value,pri,id; 11 }Tnode[N]; 12 int ans[N][3]; 13 void dfs(int now) 14 { 15 if(now==-1) 16 return; 17 int id=Tnode[now].id,ll=Tnode[now].left,rr=Tnode[now].right; 18 if(ll!=-1) 19 { 20 ans[id][1]=Tnode[ll].id; 21 ans[Tnode[ll].id][0]=id; 22 dfs(ll); 23 } 24 if(rr!=-1) 25 { 26 ans[id][2]=Tnode[rr].id; 27 ans[Tnode[rr].id][0]=id; 28 dfs(rr); 29 } 30 } 31 struct data 32 { 33 int v,p,id; 34 bool operator<(const data &ne)const 35 { 36 return v<ne.v; 37 } 38 }po[N]; 39 int stk[N],top; 40 int main() 41 { 42 int n; 43 scanf("%d",&n); 44 memset(ans,0,sizeof(ans)); 45 for(int i=1; i<=n; i++) 46 { 47 scanf("%d%d",&po[i].v,&po[i].p); 48 po[i].id=i; 49 } 50 sort(po+1,po+n+1); 51 Tnode[0].left=Tnode[0].right=-1; 52 Tnode[0].pri=-10000000; 53 top=1; 54 stk[0]=0; 55 for(int i=1;i<=n;i++) 56 { 57 int v=po[i].v,p=po[i].p,d=po[i].id; 58 while(top>0&&Tnode[stk[top-1]].pri>p) 59 top--; 60 Tnode[i].left=Tnode[stk[top-1]].right; 61 Tnode[stk[top-1]].right=i; 62 Tnode[i].right=-1; 63 Tnode[i].value=v; 64 Tnode[i].pri=p; 65 Tnode[i].id=d; 66 stk[top++]=i; 67 } 68 dfs(0); 69 printf("YES\n"); 70 for(int i=1; i<=n; i++) 71 printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]); 72 return 0; 73 }