題意:有n座城池,m個人;
每座城池有乙個耐久度;
每座城池有乙個父親城池(肯定會形成一棵樹),還有flag base (這個看題意)
每個人有乙個戰力值和乙個開始進攻的城池序號;
問:1.每個城池能夠使將領死亡的死亡數 2.每個將領能夠攻占的城池數量;
思路,這道題是一顆樹,所以自然而然的想到用dfs傳到根節點,再傳回去這種做法;
那麼在這種做法下,我們建立最小堆,對每乙個節點建立乙個最小堆,然後遍歷的時候,將小於limit的將領彈出;
這個時候需要更新答案, 這個城池的將領死亡數量+1;這個將領攻占的城池數量;
然後 剩下的將領有乙個val需要更新 這個時候我們不是直接更新,而是用乙個懶惰節點去降低複雜度;
一步一步傳給子節點更新;
1 #include2 #include3 #include4 #include5using
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並...