poj 2201(RMQ+笛卡尔树)
給出一些結(jié)點(diǎn)
每個節(jié)點(diǎn)有兩個關(guān)鍵字
要求構(gòu)造一棵樹
第一個關(guān)鍵字滿足二叉搜索樹的性質(zhì),第二個關(guān)鍵字滿足小堆的性質(zhì)
解題思路:這道題我開始是用第二關(guān)鍵字從小到大排序,然后從1-n去添加節(jié)點(diǎn)。這樣是符合最小堆的性質(zhì),假設(shè)添加第i個節(jié)點(diǎn),那么首先去找[1,i-1]這段區(qū)間的第一關(guān)鍵字的最小值和最大值,如果i節(jié)點(diǎn)的第一關(guān)鍵字大于最大值,就直接添加到最大值節(jié)點(diǎn)的右兒子,如果小于最小值,就添加到最小值節(jié)點(diǎn)的左兒子,否則就直接從根節(jié)點(diǎn)往下找。可是超時了,其實(shí)超時的原因還蠻明顯的,因為你添加的i節(jié)點(diǎn)不一定每次都是大于最大值,小于最小值,更多的情況可能是在中間值,這樣每次都要從根節(jié)點(diǎn)出發(fā)往下走,這樣就會造成遍歷的時間太多了。但按照這種思路,很難直接找到i節(jié)點(diǎn)的父節(jié)點(diǎn)是誰,因為[1,i-1]區(qū)間內(nèi)的第一關(guān)鍵字是無序的。
參考了網(wǎng)上的思路,絕大部分都是按照第一關(guān)鍵字排序,然后再去找區(qū)間段內(nèi)的最小值作為子樹的根節(jié)點(diǎn)。
http://blog.csdn.net/sdj222555/article/details/7909198
我的TLE:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std;const int maxn = 50005; struct Node {int k,a;int id;bool operator < (const Node &T){return a < T.a;} }tree[maxn]; struct Result {int parent,left,right; }res[maxn]; int n,value[maxn],dp_max[maxn][20],dp_min[maxn][20];int _max(int l,int r) {if(tree[l].k > tree[r].k) return l;return r; }int _min(int l,int r) {if(tree[l].k < tree[r].k) return l;return r; }void initRMQ() {for(int i = 1; i <= n; i++)dp_max[i][0] = dp_min[i][0] = i;for(int j = 1; (1 << j) <= n; j++)for(int i = 1; i + (1 << j) - 1 <= n; i++){dp_max[i][j] = _max(dp_max[i][j-1],dp_max[i+(1<<j-1)][j-1]);dp_min[i][j] = _min(dp_min[i][j-1],dp_min[i+(1<<j-1)][j-1]);} }int MaxValue(int l,int r) {int k = (int)(log((r - l + 1)*1.0) / log(2.0));return _max(dp_max[l][k],dp_max[r-(1<<k)+1][k]); }int MinValue(int l,int r) {int k = (int)(log((r - l + 1)*1.0) / log(2.0));return _min(dp_min[l][k],dp_min[r-(1<<k)+1][k]); }void Build() {int maxm,minm;for(int i = 1; i <= n; i++)res[i].parent = res[i].left = res[i].right = 0;for(int i = 2; i <= n; i++){maxm = MaxValue(1,i-1);minm = MinValue(1,i-1);if(tree[i].k > tree[maxm].k){res[tree[maxm].id].right = tree[i].id;res[tree[i].id].parent = tree[maxm].id;}else if(tree[i].k < tree[minm].k){res[tree[minm].id].left = tree[i].id;res[tree[i].id].parent = tree[minm].id;}else{int p = tree[1].id;while(true){if(tree[i].k > value[p]){if(res[p].right != 0)p = res[p].right;else{res[p].right = tree[i].id;res[tree[i].id].parent = p;break;}}else{if(res[p].left != 0)p = res[p].left;else{res[p].left = tree[i].id;res[tree[i].id].parent = p;break;}}}}} }int main() {while(scanf("%d",&n)!=EOF){for(int i = 1; i <= n; i++){scanf("%d%d",&tree[i].k,&tree[i].a);tree[i].id = i;value[i] = tree[i].k;}sort(tree+1,tree+1+n);initRMQ();Build();printf("YES\n");for(int i = 1; i <= n; i++)printf("%d %d %d\n",res[i].parent,res[i].left,res[i].right);}return 0; }
總結(jié)
以上是生活随笔為你收集整理的poj 2201(RMQ+笛卡尔树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: poj 2452(RMQ+二分)
- 下一篇: 如何自定义 maven中的archety