GDKOI2014「内存分配」

题目

Description
小明的机器上运行着 n n n 个程序 P 1 , P 2 , … , P n P_1,P_2,…,P_n P1,P2,,Pn ,其中程序 P i P_i Pi 占用着 a i a_i ai 个单位的内存,仍需要 b i b_i bi 个单位的内存这个程序才能结束。小明可以为程序 P i P_i Pi 分配至少 b i b_i bi 个单位的空闲内存,结束这个程序。当程序 P i P_i Pi 结束的时候,它会把它之前占用的 a i a_i ai 个单位的内存和分配的 b i b_i bi 个单位的内存一起释放,而小明可以把这些内存回收回来,与原来的空闲内存组成新的空闲内存小明想知道,他机器上的空闲内存至少应该是多少个单位,他的所有程序才有可能全部运行完。除此之外,每经过一分钟,小明的机器上都有一个程序 P j P_j Pj 发生改变,即 a j , b j a_j,b_j aj,bj 变成了 a j ′ , b j ′ a'_j,b'_j aj,bj。注意,同一个程序有可能会变化多次。你能帮小明计算,每次程序发生变化之后,系统上的空闲内存至少应该是多少个单位吗?

Sample Input

2 3
1 4
1 4
2 2 1
2 1 1
1 1 1

Sample Output

2
3
1

思路

把所有程序按照所需空间从小到大排好序,全部合并起来就可以得出最终答案,也就是树根。
对于修改操作,需要把所有程序(包括修改后)全部按照所需空间排序,一开始把所有原程序的位置从空程序修改为它本身。
修改时把原程序在所有程序排名的那个节点变成空程序 (0,0),再把新程序的位置从空程序变成新的程序 (a,b) 。只需要在线段树上单点修改就可以解决了。(竟然真的用到了!!单点修改!!)
时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <cstdio>
#include <algorithm>
#define re register
using namespace std;
#define maxn 100005
#define _maxn 1000005

typedef long long ll;
struct node {
	int a, b, site, num;
} T[200005];
int qry[maxn], orig[maxn];
ll a[_maxn], b[_maxn];
bool exist[_maxn];

bool cmp(node x, node y) {
	return x.b<y.b || x.b==y.b && x.a>y.a;
}

void push_up(int now) {
	int L_son=now<<1, R_son=now<<1|1;
	a[now]=a[L_son]+a[R_son];
	b[now]=max(b[L_son], b[R_son]-a[L_son]);
}

void build(int now, int L, int R) {
	if (L==R) {
		if (!T[L].num) {
			a[now]=T[L].a;
			b[now]=T[L].b;
			exist[now]=1;
		}
		return;
	}
	
	int mid=(L+R)>>1;
	int L_son=now<<1, R_son=now<<1|1;
	build(L_son, L, mid);
	build(R_son, mid+1, R);
	
	push_up(now);
}

void update(int now, int L, int R, int x) {
	if (L==R) {
		if (exist[now]) {
			a[now]=b[now]=0;
			exist[now]=0;
		}
		else {
			a[now]=T[L].a;
			b[now]=T[L].b;
			exist[now]=1;
		}
		return;
	}
	
	int mid=(L+R)>>1;
	int L_son=now<<1, R_son=now<<1|1;
	if (x<=mid) {
		update(L_son, L, mid, x);
	}
	else {
		update(R_son, mid+1, R, x);
	}
	
	push_up(now);
}

int n, m;
int main() {
	scanf("%d %d", &n, &m);
	for (re int i=1; i<=n; i++) {
		scanf("%d %d", &T[i].a, &T[i].b);
		T[i].num=0; T[i].site=i;
	}
	
	for (re int i=n+1; i<=n+m; i++) {
		scanf("%d %d %d", &T[i].site, &T[i].a, &T[i].b);
		T[i].num=i-n;
	}
	
	sort(T+1, T+n+m+1, cmp);
	
	for (re int i=1; i<=n+m; i++) {
		if (T[i].num) qry[T[i].num]=i;
		else orig[T[i].site]=i;
	}
	
	build(1, 1, n+m);
	
	for (re int i=1; i<=m; i++) {
		update(1, 1, n+m, orig[T[qry[i]].site]);
		orig[T[qry[i]].site]=qry[i];
		update(1, 1, n+m, qry[i]);
		printf("%lld\n", b[1]);
	}
	
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值