JZOJ5456 奇怪的佇列 線段樹

2022-09-03 04:36:09 字數 2430 閱讀 3688

題目:

給出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...