左偏樹 (p3261 對我來說是一道高階題

2022-06-02 08:06:08 字數 1760 閱讀 4888

題意:有n座城池,m個人;

每座城池有乙個耐久度;

每座城池有乙個父親城池(肯定會形成一棵樹),還有flag base (這個看題意)

每個人有乙個戰力值和乙個開始進攻的城池序號;

問:1.每個城池能夠使將領死亡的死亡數 2.每個將領能夠攻占的城池數量; 

思路,這道題是一顆樹,所以自然而然的想到用dfs傳到根節點,再傳回去這種做法;

那麼在這種做法下,我們建立最小堆,對每乙個節點建立乙個最小堆,然後遍歷的時候,將小於limit的將領彈出;

這個時候需要更新答案, 這個城池的將領死亡數量+1;這個將領攻占的城池數量;

然後   剩下的將領有乙個val需要更新 這個時候我們不是直接更新,而是用乙個懶惰節點去降低複雜度;

一步一步傳給子節點更新;

1 #include2 #include3 #include4 #include

5using

namespace

std;

6 typedef long

long

ll;7

const ll maxn=3e5+10

;8 ll flag[maxn],base[maxn]; //

城池的val更新方式

9 ll ch[maxn][2]; //

子節點10 ll val[maxn],guishu[maxn]; //

將領的戰力值和第乙個城池

11 ll root[maxn]; //

每乙個城池的根節點;

12 ll dep[maxn],dis[maxn]; //

dep是用來計算將領的攻占城池數量的, dis是左偏樹的深度;

13 ll ans1[maxn],ans2[maxn]; //

城池答案,將領答案;

14 ll mul[maxn],add[maxn]; //

懶惰標記

15 ll limit[maxn]; //

城池耐久值

16struct node //

鄰接表17

g[maxn]; ll head[maxn];ll num=-1;20

void

build(ll u,ll v)

2124

void

cov(ll x,ll c,ll j)

2533

void

pushdown(ll x)

34 39

ll merge(ll x,ll y)

4049

50void

dfs(ll u,ll fa)

5158

while(root[u]&&val[root[u]]65if(flag[u]) cov(root[u],base[u],0

);66

else cov(root[u],1,base

[u]);67}

68int

main()

6979

for(ll i=1;i<=m;i++)

86 dfs(1,0

);87

while(root[1

])92

for(ll i=1;i<=n;i++) printf("

%lld\n

",ans1[i]);

93for(ll i=1;i<=n;i++) printf("

%lld\n

",ans2[i]);

94return0;

95 }

洛谷P3261 城池攻占

臭不要臉的把 loj 的題面截圖下來 乙個顯然的思路是從葉子往上跑,將所有可以到點 x 的騎士扔進乙個小根堆裡面,然後不停彈出堆頂直到對頂元素的值不小於 h x 或者堆空了。由於需要堆合併,所以直接上左偏樹即可。至於乘和加就在堆頂打 tag,然後合併或彈出的時候再 pushdown 即可。順序顯然是...

P3261 JLOI2015 城池攻占 左偏樹

小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城池 i 會受到另一座城池 fi 的管轄,其中 fi 每個城池有乙個防禦值 hi,如果乙個騎士的戰鬥力大於等於城池的生命值,那麼騎士就可以占領這座城池 否則占領失敗,騎...

P3377 左偏樹,模板)

題意 如題,一開始有n個小根堆,每個堆包含且僅包含乙個數。接下來需要支援兩種操作 操作1 1 x y 將第x個數和第y個數所在的小根堆合併 若第x或第y個數已經被刪除或第x和第y個數在用乙個堆內,則無視此操作 操作2 2 x 輸出第x個數所在的堆最小數,並將其刪除 若第x個數已經被刪除,則輸出 1並...