題目:
給出nn
個人的身高,第i
i個人記得他的前面或者後面有a[i
]a[i
]個人比他高。這些人字典序最小的排列。
40分做法:
先將所有人的身高排序,然後dfs
dfs全排列,再判斷是否成立。
時間複雜度:o(n
!n2)
o(n!
n2)**
100分做法:
按照樣例一來模擬
4
4 13 1
6 02 0
先按身高排序(從小到大)
4
2 03 1
4 16 0
首先,我們有乙個長度為4的空串
身高為2,前(後)面有0個人比他高的人。那麼很明顯,就只能插入第乙個或最後乙個位置。
為了字典序最小,那麼就將這個人插入到第乙個位置。
然後看下乙個人,身高為3,前(後)面有乙個人比他高。
那麼可能的位置也就只有乙個,就插入三號位。
身高為4,前(後)面沒有人比他高。
那麼剩餘兩個位置都有可能。
選擇字典序更小的。
那麼最後乙個人就只能放在最後乙個位置了。
那麼,我們就需要乙個可以插入和查詢的資料結構
。那麼很容易想到權值線段樹。
然後就迎刃而解了。
#include
#include
#define n 100100
using
namespace std;
int n,ans[n]
,f;char c;
struct node
p[n]
;struct tree
tree[n*3]
;int
read()
return f;
}void
write
(int x)
bool
cmp(node x,node y)
void
make
(int x)
//建樹
int mid=
(tree[x]
.l+tree[x]
.r)/2;
tree[x*2]
.l=tree[x]
.l; tree[x*2]
.r=mid;
tree[x*2+
1].l=mid+1;
tree[x*2+
1].r=tree[x]
.r;make
(x*2);
make
(x*2+1
);tree[x]
.num=tree[x*2]
.num+tree[x*2+
1].num;
}void
find
(int x,
int num,
int h)
//查詢
if(num
.num)
find
(x*2
,num,h)
;//可以往左就往左
else
find
(x*2+1
,num-tree[x*2]
.num,h);}
intmain()
tree[1]
.l=1
; tree[1]
.r=n;
make(1
);for(
int i=
1;i<=n;i++
)find(1
,min
(p[i]
.s,n-p[i]
.s-i)
,p[i]
.h);
for(
int i=
1;i<=n;i++
)return0;
}
JZOJ5456 奇怪的佇列 線段樹
題目 給出nn n個人的身高,第i ii個人記得他的前面或者後面有a i a i a i 個人比他高。這些人字典序最小的排列。40分做法 先將所有人的身高排序,然後dfs dfsdf s全排列,再判斷是否成立。時間複雜度 o n n2 o n n 2 o n n2 100分做法 按照樣例一來模擬 4...
UNR 1 奇怪的線段樹
一道好題,感覺解法非常自然。首先我們只需要考慮一次染色最下面被包含的那些區間,因為把無解判掉以後只要染了乙個節點,它的祖先也一定被染了。然後發現一次染色最下面的那些區間一定是一段連續的左兒子 一段連續的右兒子。證明的話可以看官方題解,感性理解的話不難,同時,任意一段連續的左兒子 右兒子也對應乙個區間...
Jzoj4747 被粉碎的線段樹
額這個題麼 有乙個很關鍵的點 結點個數依然為2n 1 證明可以看sam的講稿 不難發現以下性質 區間定位個數 區間所覆蓋的節點個數 2 區間長度 所以問題變為,乙個區間覆蓋了多少個節點?我們可以求出所有的節點,然後這個問題就是乙個二維偏序計數問題了 具體用離線 按照r排序套上樹狀陣列即可 inclu...