JLOI2015 城池攻占

2022-05-05 18:06:14 字數 1550 閱讀 2258

傳送門

題目的意思描述非常明確,我們很容易想到最暴力的演算法——模擬!

不知道o(nm)的模擬能拿到多少分,反正肯定會t飛的。

我們考慮優化一下,因為各個騎士之間是獨立的,但是我們的問題是乙個乙個列舉騎士複雜度過高,我們可以用全域性變數來記錄一下每乙個騎士團的情況。這樣的話,我們對於每乙個被攻擊的城池建立一棵左偏樹,維護當前攻占到這個城池的騎士,然後把戰鬥力小於城池防禦力的騎士踢出去即可。

刪除的複雜度最多是o(mlogm),建立左偏樹最多也是o(mlogm),瓶頸出現在兩棵左偏樹合併上。因為不同的騎士團攻打到同乙個城池的時候,他們之前獲得的buff可能是不同的,我們不能把兩個騎士團的情況全都計算之後再正常合併,那樣又會t的。解決的方法就是像線段樹一樣打上標記,注意要先乘後加(這個就和線段樹模板是一樣的了),每次在合併和刪除操作的時候都要下放標記。

這樣合併就可以了,最後我們記錄答案的話,在向下dfs的過程中記錄一下每個點的深度,之後就能知道這個騎士一共攻占過幾個城池了。

看一下**。

#include#include

#include

#include

#include

#include

#include

#define rep(i,a,n) for(int i = a;i <= n;i++)

#define per(i,n,a) for(int i = n;i >= a;i--)

#define enter putchar('\n')

using

namespace

std;

typedef

long

long

ll;const

int m = 300005

;const

int inf = 1000000009

;ll read()

while(ch >= '

0' && ch <= '9'

)

return ans *op;

}struct

edge

e[m<<1

];int

n,m,c[m],f[m],dead[m],lc[m],rc[m],size[m],dep[m],kill[m],ecnt,head[m],root[m],dis[m];

ll h[m],v[m],s[m],mul[m],add[m],sum[m];

bool

ml[m];

void adde(int x,int

y)void cover(int

x,ll a,ll b)

void pushdown(int

x)int merge(int x,int

y)int split(int

x)void dfs(int x,int

fa)

if(ml[x]) cover(root[x],v[x],0

);

else cover(root[x],1

,v[x]);

}int

main()

JLOI2015 城池攻占

霧.改變操作乘法是沒有負數的,那麼就不會改變大小關係,我們就可以dfs樹,然後用可合併堆進行操作。splay 啟發式合併也可以過 luogu 3261 bzoj 4003 include include include define int long long const int maxm 3100...

JLOI2015 城池攻占

點此看題 先把每個人放到對應的點上,可以用左偏樹,然後從下往上合併,每次就刪除當前節點會犧牲的人,然後維護乙個 加法 乘法 標記,時間複雜度o n log n o n log n o nlogn include include using namespace std define int long ...

JLOI2015 城池攻占

原題位址 首先發現乘的時候 係數不會為負,所以能得到乙個關鍵條件 變化後的戰鬥力隨變化前的戰鬥力大小單調 所以我們考慮倍增 設hp x i 是從x開始一路攻克 2 i 個城池所需要最小的初始生命值 設trans x i 0 1 是攻克了 2 i 個城池後攻擊力的變化量,0表示乘,1表示加,先乘後加 ...