xdoj1065 Efficent Allocation 动态开点的线段树

xdoj1065 Efficent Allocation  动态开点的线段树

1065: Efficent Allocation

时间限制: 8 Sec  内存限制: 256 MB
提交: 24  解决: 3
[提交][状态][讨论版]

题目描述

由于XDOJ评测机的一些奇怪行为,本题时限调整到8s



lx正在写一个内存分配器,支持下列操作:

(1) malloc(size),分配一个大小为size字节的内存块,返回指向该内存块的指针。

(2) free(p),释放起始地址是p的内存块。

lx使用的分配策略是:每次找出一段地址最低的,大小不小于size字节的未分配内存,然后把这段内存的size字节分配出来,剩余的部分仍然是未分配内存。在释放内存时,把被释放的内存块和前后的未分配内存合并成一块更大的未分配内存。

这时lw告诉lx,该分配器可能运行缓慢,并且产生大量内存碎片。lx承认了前一点,但是对于后一点十分不服气。于是,lw决定模拟该分配器的行为以证明这一点。但是,这个分配器太慢了,因此lw需要用一个较快的方法模拟该分配器的行为。

假设分配器管理的内存地址从1开始,即可供分配的内存是[1,n]

输入

多组数据(最多5组)。

每组数据,第一行,两个整数n、q,表示分配器管理的内存大小和操作的个数。
之后q行,每行是malloc(size)或free(p),含义如题目描述所述。

数据保证:1<=n<=109,1<=q<=100000,1<=size<=n,p是之前已经分配的某个内存块的起始地址。

输出

对于每次malloc操作输出1行,若操作成功,输出分配的内存块的起始地址(十进制)。若分配失败,输出0

样例输入

100 2
malloc(100)
free(1)
5 8
malloc(1)
malloc(1)
malloc(1)
malloc(1)
free(1)
free(3)
malloc(2)
free(4)

样例输出

1
1
2
3
4
0

提示

对于第二组样例,在第6次操作后,已经分配的内存块是[2,2]和[4,4],空闲内存块是[1,1]、[3,3]和[5,5]。它们的大小都小于2,因此分配失败。

来源

XDU 2015.6月赛

对拍了无数组小数据都过了,然而还是WA了。。。一定是标程的问题。

代码:

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=6500100;
const int INF=(1<<29);

struct Node
{
    int l,r;
    int ms,ls,rs;
    int tag;
    int lch,rch;
};

struct SegTree
{
    Node T[maxn];
    int p,rt;
    int newnode(int l,int r,int has)
    {
        T[++p]=(Node){l,r,(r-l+1)*has,(r-l+1)*has,(r-l+1)*has,has,-1,-1};
        return p;
    }
    void init(int l,int r)
    {
        p=0;
        rt=newnode(l,r,1);
    }
    void push_down(int rt)
    {
        if(T[rt].lch==-1&&T[rt].rch==-1) return;
        if(T[rt].tag!=-1){
            int lch=T[rt].lch,rch=T[rt].rch,tag=T[rt].tag;
            T[lch].tag=T[rch].tag=tag;
            T[lch].ms=T[lch].ls=T[lch].rs=tag*(T[lch].r-T[lch].l+1);
            T[rch].ms=T[rch].ls=T[rch].rs=tag*(T[rch].r-T[rch].l+1);
            T[rt].tag=-1;
        }
    }
    void push_up(int rt)
    {
        int lch=T[rt].lch,rch=T[rt].rch;
        T[rt].ls=T[lch].ls;
        T[rt].rs=T[rch].rs;
        if(T[rt].ls==T[lch].r-T[lch].l+1) T[rt].ls+=T[rch].ls;
        if(T[rt].rs==T[rch].r-T[rch].l+1) T[rt].rs+=T[lch].rs;
        T[rt].ms=max(max(T[lch].ms,T[rch].ms),T[lch].rs+T[rch].ls);
    }
    int query(int siz,int rt)
    {
        if(T[rt].ms<siz) return 0;
        if(T[rt].ls>=siz) return T[rt].l;
        push_down(rt);
        int t=query(siz,T[rt].lch);
        if(t) return t;
        int m=(T[rt].l+T[rt].r)>>1;
        if(T[T[rt].lch].rs+T[T[rt].rch].ls>=siz) return m-T[T[rt].lch].rs+1;
        return query(siz,T[rt].rch);
    }
    void update(int L,int R,int c,int rt)
    {
        int l=T[rt].l,r=T[rt].r;
        if(L<=l&&r<=R){
            T[rt].ms=T[rt].ls=T[rt].rs=(r-l+1)*c;
            T[rt].tag=c;
            return;
        }
        int m=(l+r)>>1;
        if(T[rt].lch==-1&&T[rt].rch==-1){
            T[rt].lch=newnode(l,m,T[rt].tag);
            T[rt].rch=newnode(m+1,r,T[rt].tag);
        }
        push_down(rt);
        if(L<=m) update(L,R,c,T[rt].lch);
        if(R>m) update(L,R,c,T[rt].rch);
        push_up(rt);
    }
};SegTree sgt;
int n,q;
char op[maxn];int x;

int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    while(cin>>n>>q){
        sgt.init(1,n);
        while(q--){
            scanf("%s",op);
            if(op[0]==‘m‘){
                sscanf(op,"malloc(%d)",&x);
                int L=sgt.query(x,sgt.rt);
                printf("%d\n",L);
                if(L) sgt.update(L,L+x-1,0,sgt.rt);
            }
            else{
                sscanf(op,"free(%d)",&x);
                sgt.update(x,x,1,sgt.rt);
            }
        }
    }
    return 0;
}

暴力代码:

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

int a[maxn];
int n,q;
char op[maxn];int x;

int query(int x)
{
    for(int i=1;i<=n;){
        if(a[i]){
            bool tag=1;
            int j;
            for(j=i;j<=i+x-1;j++){
                if(a[j]) continue;
                else{
                    tag=0;break;
                }
            }
            if(tag) return i;
            else i=j+1;
        }
        else i++;
    }
    return 0;
}

void update(int L,int R,int c)
{
    REP(i,L,R) a[i]=c;
}

int main()
{
    freopen("in.txt","r",stdin);
    freopen("out_duipai.txt","w",stdout);
    while(cin>>n>>q){
        MS0(a);
        REP(i,1,n) a[i]=1;
        while(q--){
            scanf("%s",op);
            if(op[0]==‘m‘){
                sscanf(op,"malloc(%d)",&x);
                int L=query(x);
                printf("%d\n",L);
                if(L) update(L,L+x-1,0);
            }
            else{
                sscanf(op,"free(%d)",&x);
                update(x,x,1);
            }
        }
    }
    return 0;
}

数据生成器:

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

int n,q;
int op,x;

int main()
{
    freopen("in.txt","w",stdout);
    int T=1000;
    while(T--){
        n=rand()%71+1;q=rand()%1000+1;
        printf("%d %d\n",n,q);
        while(q--){
            op=rand()%2+1;x=rand()%n+1;
            if(op==1) printf("malloc(%d)\n",x);
            else printf("free(%d)\n",x);
        }
    }
    return 0;
}

对拍:

#include<bits/stdc++.h>
#include<windows.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=(1<<29);

int x,y;

int main()
{
    FILE *fp=fopen("out.txt","r"),*fp1=fopen("out_duipai.txt","r");
    int tag=1;
    while(~fscanf(fp,"%d",&x)){
        fscanf(fp1,"%d",&y);
        if(x==y) puts("ok");
        else{
            printf("wrong x=%d y=%d\n",x,y);
            tag=0;
            Sleep(1000);
        }
    }
    puts(tag?"Accept":"Wrong");
    return 0;
}

时间: 2024-10-24 04:36:31

xdoj1065 Efficent Allocation 动态开点的线段树的相关文章

xdoj1023 IP查询 动态开点的线段树

xdoj1023 IP查询    动态开点的线段树 1023: IP查询 时间限制: 1 Sec  内存限制: 128 MB提交: 3473  解决: 228[提交][状态][讨论版] 题目描述 现实生活中,每一个IP段都指向一座城市.为了简化问题,我们将IP段直接看做一个整形数,每座城市也有自己的唯一标识ID,也可以看做一个整数.那么问题来了,现在已知有多个闭区间代表多个IP段,每个区间对应一个城市的ID.现在,小L要查询某个IP属于那个城市,希望聪明的你来帮他完成. 输入 第一行输入T,表示

扫描线讲解,动态开点版线段树

扫描线 首先,扫描线是干什么的?扫描线一般运用在图形上面,它和它的字面意思十分相似,就是一条线在整个图上扫来扫去,它一般被用来解决图形面积,周长等问题,以一道例题为例.给出n个正方形,这些正方形在平面直角坐标系中互相重叠摆放,但四条边都与坐标轴平行,例如下图所示.那么知道题目了,怎么运用呢?首先我们需要知道怎么用暴力解决这个问题,根据图片可知图中的面积是SABCD+SHEFG-SIDJE暴力搜索是个好东西,但是当数据范围大了怎么办?这里就要讲到扫描线. 扫描线对于这道例题可以抽象为这四条紫色的直

zoj 2112 Dynamic Rankings 动态第k大 线段树套Treap

Dynamic Rankings Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2112 Description The Company Dynamic Rankings has developed a new kind of computer that is no longer satisfied with the query l

【BZOJ-1568】Blue Mary开公司 李超线段树 (标记可持久化)

1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 557  Solved: 192[Submit][Status][Discuss] Description Input 第一行 :一个整数N ,表示方案和询问的总数. 接下来N行,每行开头一个单词“Query”或“Project”. 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益. 若单词为Project,则后

算法学习——动态图连通性(线段树分治+按秩合并并查集)

在考场上遇到了这个的板子题,,,所以来学习了一下线段树分治 + 带撤销的并查集. 题目大意是这样的:有m个时刻,每个时刻有一个加边or撤销一条边的操作,保证操作合法,没有重边自环,每次操作后输出当前图下所有联通块大小的乘积. 首先观察到如果没有撤销操作,那么直接用并查集就可以维护,每次合并的时候乘上要合并的两个并查集大小的逆元,然后乘上合并之后的大小即可. 那么来考虑撤销,观察到如果并查集不带路径压缩,应该是可以处理撤销操作的. 但我们并不能直接做,因为并查集的撤销必须按顺序来,就相当于每次合并

【BZOJ3939】Cow Hopscotch(动态开点线段树)

题意: 就像人类喜欢跳格子游戏一样,FJ的奶牛们发明了一种新的跳格子游戏.虽然这种接近一吨的笨拙的动物玩跳格子游戏几乎总是不愉快地结束,但是这并没有阻止奶牛们在每天下午参加跳格子游戏 游戏在一个R*C的网格上进行,每个格子有一个取值在1-k之间的整数标号,奶牛开始在左上角的格子,目的是通过若干次跳跃后到达右下角的格子,当且仅当格子A和格子B满足如下条件时能从格子A跳到格子B: 1.B格子在A格子的严格右方(B的列号严格大于A的列号) 2.B格子在A格子的严格下方(B的行号严格大于A的行号) 3.

HDU6183 Color it 动态开点线段树

网址:https://vjudge.net/problem/HDU-6183 题意: 给出以下操作:$“0”$代表清空所有颜色,$"1$ $x$ $y$ $c$$"$代表在坐标$(x,y)$涂上第$c$种颜色,$"2$ $x$ $y_1$ $y_2$$"$代表统计$x$轴上$[1,x]$和y轴上$[y_1,y_2]$的颜色数,一个点可以有多种颜色,$“3”$代表结束.数据保证$n,m \leq 1e6,0 \geq c \leq 50,y_1 \leq y_2$.

【BZOJ2733】永无乡(线段树合并)

题意:支持合并,求块内K小数 对于 100%的数据 n≤100000,m≤n,q≤300000 思路:对于每一个块建立一棵动态开点的线段树,暴力(启发式?)合并后二分下就行了 merge用函数的方式写因为懒得讨论x,y其中一个为0的情况,反正是把节点y并到x上 为什么这么暴力都不T?大概是因为随机数据的块的大小太平均了吧 var t:array[0..2100000,0..1]of longint; sum:array[0..2100000]of longint; fa,a,root:array

[XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动态开点. 线段树的节点维护两个值,一个是这段时间内的 1 操作个数,另一个是这段时间内变化的黑色节点权值和. 在处理所有操作的时候,每棵线段树都是仅代表树上的一个点,因此线段树的每个节点维护的就是这段时间内以这个点为 a 的 1 操作个数和这段时间内这个点的黑色节点权值和(这个点 x 由黑变白就 -