bzoj 4003
需要實現乙個可並堆。
每個點維護乙個小根堆,然後一開始把所有騎士加入到它所在的點的小根堆當中,實際上空間是$o(m)$的,然後我們從上到下不斷合併這個小根堆,合併完之後如果遇到堆頂小於當前城市的防禦值就彈掉堆頂順便記錄答案。
對於那些攻占掉城池對騎士的貢獻的處理,可以採用打標記的方式實現,在合併的時候$down$一下就好了。注意$down$要寫在$merge$函式的最上面,因為有一些點還沒有下傳標記就被$merge$掉了。
要注意彈出堆頂元素之前要先$down$一下 。
最後在清空一下第乙個堆中的元素就好了。
不會算時間複雜度$qωq$。
code:
//view codeluogu-judger-enable-o2
#include #include
using
namespace
std;
typedef
long
long
ll;const
int n = 3e5 + 5
;int n, m, tot = 0
, head[n], type[n], dep[n], ans[n];
ll def[n], rat[n];
struct
knight a[n];
struct
edge e[n
<< 1
];inline
void add(int
from, int
to)
template
inline
void read(t &x)
template
inline
void swap(t &x, t &y)
namespace
leftlisttree s[n];
#define lc(p) s[p].lc
#define rc(p) s[p].rc
#define key(p) s[p].key
#define multag(p) s[p].multag
#define addtag(p) s[p].addtag
#define dis(p) s[p].dis
#define id(p) s[p].id
int root[n], nodecnt = 0
;
inline
int newnode(int
p)
inline
void down(int
p)
if(rc(p))
multag(p) = 1
; }
if(addtag(p) != 0
)
if(rc(p))
addtag(p) = 0
; }
}int merge(int x, int
y)
} using
namespace
leftlisttree;
void solve(int x, int fat, int
depth)
for(; root[x] && key(root[x])
if(root[x])
else
}}int
main()
for(int i = 1; i <= m; i++)
solve(
1, 0, 1
);
for(int i = 1; i <= n; i++)
printf(
"%d\n
", ans[i]);
for(; root[1
]; )
for(int i = 1; i <= m; i++)
printf(
"%d\n
", dep[a[i].pos] -dep[a[i].ed]);
return0;
}
luogu 3261 JLOI2015 城池攻占
小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城池 i 會受到另一座城池 fi 的管轄,其中 fi 中第 i 個騎士的初始戰鬥力為 si,第乙個攻擊的城池為 ci。每個城池有乙個防禦值 hi,如果乙個騎士的戰鬥力大...
P3261 JLOI2015 城池攻占
p3261 jloi2015 城池攻占 乍一看,平衡樹?其實左偏樹更好做啦 qwq 每個節點都來棵左偏樹維護最小值,dfs 往上時合併一下,要是攻不下了就把根節點刪掉,直到能攻下,對了,攻下後值會變化怎麼辦?lazy 標記一下,和線段樹同理 include includeusing namespac...
LG P3261 JLOI2015 城池攻占
小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城池 i 會受到另一座城池 fi 的管轄,其中 fi 每個城池有乙個防禦值 hi,如果乙個騎士的戰鬥力大於等於城池的生命值,那麼騎士就可以占領這座城池 否則占領失敗,騎...