洛谷P3261 城池攻占

2022-06-13 15:00:10 字數 1286 閱讀 2270

臭不要臉的把 loj 的題面截圖下來

乙個顯然的思路是從葉子往上跑,將所有可以到點 \(x\) 的騎士扔進乙個小根堆裡面,然後不停彈出堆頂直到對頂元素的值不小於 \(h[x]\) 或者堆空了。

由於需要堆合併,所以直接上左偏樹即可。至於乘和加就在堆頂打 tag,然後合併或彈出的時候再 pushdown 即可。順序顯然是先乘後加。

對於第一問,答案就是在點 \(x\) 被彈出的元素個數;對於第二問,答案是該騎士最先攻擊的點的深度減去彈出時點的深度。注意對於攻擊完點 \(1\) 依然存活的騎士並不計入 \(1\) 的答案,且不用減去 \(dep[1]\)。

時間複雜度 \(o(n\log m)\)。

#include using namespace std;

typedef long long ll;

const ll n=300010;

ll n,m,tot,head[n],fa[n],a[n],c[n],rt[n],dep[n],ans1[n],ans2[n],h[n],v[n],s[n];

struct edge

e[n];

void add(ll from,ll to)

; head[from]=tot;

}struct leftisttree

if (lazy[x][0])

lazy[x][1]=1; lazy[x][0]=0; }

ll merge(ll x,ll y)

}lt;

void dfs(ll x)

lt.pushdown(rt[x]);

while (rt[x] && lt.val[rt[x]]

if (a[x]==0) lt.lazy[rt[x]][0]+=v[x];

else lt.lazy[rt[x]][1]*=v[x],lt.lazy[rt[x]][0]*=v[x];

}int main()

lt.dis[0]=-1;

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

dfs(1);

lt.pushdown(rt[1]);

while (rt[1])

for (ll i=1;i<=n;i++) printf("%lld\n",ans1[i]);

for (ll i=1;i<=m;i++) printf("%lld\n",ans2[i]);

return 0;

}

洛谷P3261 JLOI2015 城池攻占

不得不說,這道題目是真的難,真不愧它的 省選 noi 的紫色大火題!花了我晚自習前半節課看題解,寫 又花了我半節晚自習調 真的心態 基本上改得和題解完全一樣了我才過了這道題!真的煩。沒事,那接下來我來完全把這道題搞透。part 1 理解題目 至少我一開始不知道為什麼要用左偏樹,甚至我看題解一開始也都...

洛谷P3261 JLOI2015 城池攻占

思路分析 由於這道題的資料範圍是n,m 3e5,所以我們直接輸入乙個模擬乙個是會超時的,但是我們可以在輸入所有的士兵之後把同在乙個節點的士兵一起處理,我們可以考慮建乙個堆,從深度最大的節點開始,維護乙個節點內的士兵的最小戰鬥力值,如果戰鬥力最小的士兵都能存活下來,那麼在堆中的其他士兵一定可以活下來,...

洛谷P3261 JLOI2015 城池攻占

題目大意 有 n 個點的樹,第 i 個節點有乙個權值 h i m 個騎士,第 i 個騎士攻擊力為 v i 乙個騎士可以把從它開始的連續的父親中比它小的節點攻破,攻破乙個節點可以把攻擊力加或乘乙個數 乘的數大於 0 每個騎士獨立 問每個騎士可以攻破多少個點,每個點會阻擋住多少個騎士。題解 可以把所有騎...