杂题CF1271D Portals (数据较原题加强)
题目大意
最开始,你掌控着一只有 k k k 个人的军队,你的敌人有 n n n 个城堡。
为了占领第 i i i 个城堡,你需要至少 a i a_i ai 个士兵(你游戏玩的很好,所以你并不会损失士兵)。
当你占领了第 i i i 个城堡后,你可以扩军。其中在第 i i i 个城堡,你可以得到 b i b_i bi 个士兵。
此外,在你占领了一个城堡后,你可以派至少一个兵驻守。每个城堡有一个重要值 c i c_i ci ,你的总分就是所有你派兵驻守了的城堡的 c i c_i ci 的和。
有两种方式派兵:
-
你刚占领这个城堡,可以立马派兵驻守。
-
有 m m m 条小路,其中第 i i i 条是从 u u u 通往 v v v 。保证 u > v u>v u>v 。你可以使用这条小路当且仅当你当前在 u u u ,且拥有至少一个士兵可以派往 v v v 。
显然,如果一个士兵被派去驻守,他就离开了你的军队。
你需要按照从 1 1 1 到 n n n 的顺序依次攻打。
假设你当前在 i i i ,当你攻占 i + 1 i+1 i+1 时,所有在 i i i 处的小路就不能用了。
如果在游戏中你没有足够的士兵去攻打下一座城堡,你就输了。
你的目标是在胜利的前提下最大化得分。
数据范围
1 ≤ n ≤ 3 ∗ 1 0 5 , 0 ≤ m ≤ min ( n ( n − 1 ) 2 , 3 ⋅ 1 0 5 ) , 0 ≤ k ≤ 1 0 9 1\leq n\leq 3*10^5,0\leq m\leq \min(\frac{n(n-1)}{2},3\cdot 10^5),0\leq k\leq 10^9 1≤n≤3∗105,0≤m≤min(2n(n−1),3⋅105),0≤k≤109
解题思路
我们考虑贪心,显然对于一个城市我们肯定在最后可以控制它的城市再控制它最优
我们可以对于每个城市都在最后再强行控制它,但这样可能导致失败,怎么办呢?
考虑反悔贪心,我们可以把所有已选的 c i c_i ci加到一个小根堆堆里,每次如果当前兵力小于等于 a i a_i ai就弹出对顶,同时补充一个士兵,这样一定是正确的
复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
代码
#include<bits/stdc++.h>
using namespace std;
int i,j,n,m,k,l,o,p;
int f[100005],a[100005],b[100005],c[100005];
int heap[100005],now;
struct node
{
int to,nxt;
}side[100005];
int st[100005];
inline void up(int w)
{
while (w>1&&heap[w]<heap[w/2])
{
swap(heap[w],heap[w/2]);
w/=2;
}
}
inline void down(int w)
{
while (w*2<=now)
{
int y=w*2;
if (y!=now)
{
if (heap[y]>heap[y+1]) y++;
}
if (heap[w]>heap[y])
{
swap(heap[w],heap[y]);
w=y;
}
else break;
}
}
inline void ins(int num)
{
heap[++now]=num;
up(now);
}
inline int pop()
{
if (now==0) return 0;
int q=heap[1];
heap[1]=heap[now];
--now;
down(1);
return q;
}
inline int read()
{
int f(1),x(0);
char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f*=-1;ch=getchar();}
while (isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return f*x;
}
inline void writ(int x)
{
if (x<0) putchar('-'),x=-x;
if (x/10) writ(x/10);
putchar((char)(x%10+'0'));
}
inline void write(int x)
{
writ(x);
putchar(' ');
}
inline void add(int u,int v)
{
side[i].to=v,side[i].nxt=st[u],st[u]=i;
}
int main()
{
n=read(),m=read(),k=read();
for (i=1;i<=n;i++) a[i]=read(),b[i]=read(),c[i]=read(),f[i]=i;
for (i=1;i<=m;i++) o=read(),p=read(),f[p]=max(f[p],o);
for (i=1;i<=n;i++) add(f[i],i);
for (i=1;i<=n;i++)
{
while (k<a[i]&&now!=0) ++k,o=pop();
if (k<a[i])
{
printf("-1");
return 0;
}
k+=b[i];
for (j=st[i];j;j=side[j].nxt) ins(c[side[j].to]),--k;
while (k<0) ++k,o=pop();
}
p=0;
while (now>0) o=pop(),p+=o;
printf("%d",p);
}