一開始看漏條件了
題目保證當占領城池可以使攻擊力乘上\(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...