bzoj 4003 城池攻占 左偏樹

2022-02-27 11:43:37 字數 1536 閱讀 5622

一開始看漏條件了

題目保證當占領城池可以使攻擊力乘上\(v_i\)時,一定有\(v_i>0\)

上面這句話很重要(或者說去掉這句話就可以出成一道新題)

我們考慮在每個節點上都維護乙個最小堆

每次移動時我們讓在堆中的所有騎士一起移動

這樣我們知道:如果堆頂的騎士可以占領成功

那麼這個堆裡剩下的所有騎士都一定能夠占領成功

如果堆頂元素無法占領我們就刪去這個堆頂的元素,這樣我們最多刪除n次

最壞情況是\(o(nlogn)\)的,可以承受

所以我們還需要這個堆支援快速合併,任意乙個可並堆即可

於是我敲了一棵左偏樹上去...打標記打到手軟...第一次在堆上打標記

這個標記的正確性就由上面加粗的話保證了

這句話保證了:打標記後樹的結構不會改變

調了1h才發現是merge沒有return...

神奇的windows系統還讓我過了樣例和對拍,linux虛擬機器下直接**

#include #include #include using namespace std;

typedef long long ll;

templateinline void read(t &x)

inline int cat_max(const int &a,const int &b)

inline int cat_min(const int &a,const int &b)

inline node* newnode(int id,ll val)

inline void pushdown(node *p)

if(p->add != 0)

if(p->tag != 0)

}if(p->ch[1] != null)

if(p->add != 0)

if(p->tag != 0)

}p->mul = 1;p->tag = p->add = 0;

}node *merge(node *x,node *y)

int ans1[maxn],ans2[maxn];

inline void pop_less(int i,ll k,int p)

}ll h[maxn],v[maxn],s[maxn];

int c[maxn],fa[maxn],a[maxn];

inline void update(node *p,int i)else

}int main()

for(int i=1;i<=m;++i)else

}for(int i=n;i>=2;--i)

while(root[1] != null)

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

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

getchar();getchar();

return 0;

}

bzoj4003城池攻占 左偏樹

time limit 20 sec memory limit 128 mb submit 1312 solved 491 submit status discuss 小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城...

bzoj 4003 JLOI2015 城池攻占

小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城池 i 會受到另一座城池 fi 的管轄,其中 fi i。也就是說,所有城池構成了一棵有根樹。這 m 個騎士用 1 到 m 的整數表示,其中第 i 個騎士的初始戰鬥力為...

bzoj 4003 JLOI2015 城池攻占

小銘銘最近獲得了一副新的桌遊,遊戲中需要用 m 個騎士攻占 n 個城池。這 n 個城池用 1 到 n 的整數表示。除 1 號城池外,城池 i 會受到另一座城池 fi 的管轄,其中 fi 第 1 行包含兩個正整數 n m,表示城池的數量和騎士的數量。第 2 行包含 n 個整數,其中第 i 個數為 hi...