【时光回溯】【JZOJ3571】【GDKOI2014】内存分配

题目描述

这里写图片描述

输入

这里写图片描述

输出

输出m行,每行一个整数,代表输入中每次程序变化后系统所需要的空闲内存单位数。

样例输入

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

样例输出

2
3
1

数据范围

对于30%的数据,有1<=n,m<=1000
对于100%的数据,有1<=n,m<=100000

样例解释

这里写图片描述

解法

显然存在一种排列顺序,使得代价最小。
考虑这个排列的方式:易得b[i]<=b[j]时,代价最小。
感性证明:
假设当前所需代价为x,初始为0。
把所有代价小于等于x的程序立即完成,然后获得可以获得的内存。
直到没有完成的程序后,立即分配一单位的内存。
这样贪心可以保证正确性。


考虑合并两个程序为一个等价的程序。
(a1,b1)+(a2,b2)=(a1+a2,max(b1,b2a1))
显然把所有程序合并起来就是答案。
此外一个重要性质是,合并操作满足结合律。
这样就可以利用线段树来处理程序的合并。
离线处理即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define sqr(x) ((x)*(x))
#define ln(x,y) ll(log(x)/log(y))
using namespace std;
const char* fin="ex3571.in";
const char* fout="ex3571.out";
const ll inf=0x7fffffff;
const ll maxn=100007*2,maxt=maxn*4;
ll n,m,i,j,k,l,rank[maxn],b[maxn],d[maxn];
struct prog{
    ll get,need,id;
    void operator=(const prog &b){
        get=b.get;
        need=b.need;
        id=b.id;
    }
    prog(){
        get=need=id=0;
    }
}a[maxn],c[maxt];
prog merge(prog a,prog b){
    prog c;
    c.need=max(a.need,b.need-a.get);
    c.get=a.get+b.get;
    return c;
}
bool cmp(prog a,prog b){
    return a.need<b.need;
}
void change(ll l,ll r,ll t,ll v,const prog &v1){
    ll mid=(l+r)/2;
    if (l==r){
        c[t]=v1;
        return ;
    }
    if (v<=mid) change(l,mid,t*2,v,v1);
    else change(mid+1,r,t*2+1,v,v1);
    c[t]=merge(c[t*2],c[t*2+1]);
}
int main(){
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++){
        scanf("%d%d",&a[i].get,&a[i].need);
        a[i].id=i;
    }
    for (i=n+1;i<=n+m;i++){
        scanf("%d%d%d",&b[i],&k,&l);
        a[i].need=l;
        a[i].get=k;
        a[i].id=i;
    }
    sort(a+1,a+n+m+1,cmp);
    for (i=1;i<=n+m;i++) rank[a[i].id]=i;
    for (i=1;i<=n;i++) change(1,n+m,1,rank[i],a[rank[i]]),d[i]=rank[i];
    for (i=n+1;i<=n+m;i++){
        change(1,n+m,1,d[b[i]],c[0]);
        change(1,n+m,1,rank[i],a[rank[i]]);
        d[b[i]]=rank[i];
        printf("%lld\n",c[1].need);
    }
    return 0;
}

启发

对于这类不同排列不同答案的问题。
可以考虑合并元素;
如果元素满足结合律,那么就可以使用线段树进行合并。

posted @ 2016-10-13 22:19  hiweibolu  阅读(159)  评论(0编辑  收藏  举报