如果发现广告等破坏行为,请尽量将条目恢复到较早的版本而不是把相应内容直接删除,谢谢合作。
URAL/1037
来自"NOCOW"
< URAL
目录 |
[编辑] withflying的解题报告
维护两个堆,一个是未使用的内存块,以块的序号为关键字;另一个是正在使用的内存块,以开始使用这内存块的时间为关键字并且记录pos数组,pos[i]=j表示第i个内存块在堆中的位置为j。读入的时候,每读入一个时间就和第二个堆的堆顶元素比较一下,如果相差超过600秒,就删除这个堆顶元素,插到第一个堆去。对于申请操作,只需要删第一个堆的堆顶,插到第二个堆去即可。对于询问一个内存块b,我们查询pos[b]是否为0,是输出-,否则输出+ 并且更新第二个堆pos[b]位置的元素(下翻)。我的代码比较丑陋,供大家BS。
program cao; const maxn=100000; maxblocks=30000; waiting=600; var using,unused,pos,where:array[0..maxn] of longint; a,b,c,d,e,f,g,h,i,j,k,l,n,m,p,q,t,tmp:longint; ch:char; procedure swap(var a,b:longint); begin tmp:=a; a:=b; b:=tmp; end; procedure insert_unused(v:longint); var i,j,k:longint; begin inc(q); unused[q]:=v; i:=q; while i>1 do if unused[i]<unused[i shr 1] then begin swap(unused[i],unused[i shr 1]); i:=i shr 1; end else break; end; procedure deletetop_unused; var i,j,k:longint; begin unused[1]:=unused[q]; dec(q); i:=1; while (i shl 1)<=q do begin j:=i shl 1; if (j+1<=q)and(unused[j]>unused[j+1]) then inc(j); if unused[i]>unused[j] then swap(unused[i],unused[j]); i:=j; end; end; procedure insert_using(time,mac:longint); var i:longint; begin inc(p); using[p]:=time; pos[mac]:=p; where[p]:=mac; i:=p; while i>1 do if using[i]<using[i shr 1] then begin swap(using[i],using[i shr 1]); swap(pos[where[i]],pos[where[i shr 1]]); swap(where[i],where[i shr 1]); i:=i shr 1; end else break; end; procedure maintain_using(v:longint); var i,j,k:longint; begin i:=v; while (i shl 1)<=p do begin j:=i shl 1; if (j+1<=p)and(using[j]>using[j+1]) then inc(j); if using[i]>using[j] then begin swap(using[i],using[j]); swap(pos[where[i]],pos[where[j]]); swap(where[i],where[j]); end; i:=j; end; end; procedure deletetop_using; begin using[1]:=using[p]; pos[where[p]]:=1; pos[where[1]]:=0; where[1]:=where[p]; dec(p); if p<>0 then maintain_using(1); end; begin p:=0; q:=maxblocks; for i:=1 to maxblocks do unused[i]:=i; while not(eof) do begin read(t,ch,ch); while (p>0)and(using[1]+waiting<=t) do begin insert_unused(where[1]); deletetop_using; end; case ch of ‘+’: begin insert_using(t,unused[1]); writeln(unused[1]); deletetop_unused; readln; end; ‘.’: begin read(l); if pos[l]=0 then writeln(‘-’) else begin writeln(‘+’); using[pos[l]]:=t; maintain_using(pos[l]); readln; end; end; end; end; end.
[编辑] --------boboo的解题报告
由于时限是2s,直接做不会超时的,但比较悬。
program ural1037; var i,j,k,num,time,t:longint; ch:char; a:array[0..30000]of longint; begin for i:=1 to 30000 do a[i]:=-600; max:=1; while not seekeof do begin read(time,ch,ch); if ch='+' then begin t:=time-600; i:=1; while a[i]>t do inc(i); writeln(i); a[i]:=time; end else begin read(num); if time-a[num]>=600 then writeln('-') else begin writeln('+'); a[num]:=time; end; end; end; end.
http://hi.baidu.com/boboo%5Foi/blog/item/93a4d63f888ecceb55e7234a.html
http://hi.baidu.com/boboo_oi/blog
[编辑] Hakkinen(菜)的代码(不叫解题报告)
用两个堆,一个放用过的,一个放没用过的,供大家bs,想写线段树,但想不出来……
#include<cstdio> #include<iostream> #include<cstring> using namespace std; #define maxn 100000 #define mx 10000000 #define N 30001 typedef struct factor_ { long time; long key; }factor; typedef factor Heap[maxn]; long Pos[N*2]={0},Point[N*2]={0}; Heap H1={0},H2={0}; long Get(factor x,int type) { if (type==1) {if (!x.key) return mx;else return x.key;} if (!x.time) return mx;else return x.time; } void MinHeapfy(Heap H,long x,int type) { long Min=0; factor t; if ( x*2> H[0].key ) return; if ( Get(H[x],type) > Get(H[x*2],type) ) Min=x*2; if ( Get(H[x],type) > Get(H[x*2+1],type) && Get(H[x*2+1],type) < Get(H[x*2],type) ) Min=x*2+1; if (Min) { t=H[x];H[x]=H[Min];H[Min]=t; if (type==2) { Pos[ Point[x] ]=Min; Pos[ Point[Min] ]=x; long temp=Point[Min]; Point[Min]=Point[x]; Point[x]=temp; } MinHeapfy(H,Min,type); } return; } factor DeleteMin(Heap H,int type) { factor x=H[1]; H[1]=H[ H[0].key ]; if (type==2) { Pos[ H[H[0].key].key ]=1; Point[1]=H[1].key; Point[ H[0].key ]=0; } H[ H[0].key ].key=0; --H[0].key; MinHeapfy(H,1,type); return x; } long HeapIns(Heap H,factor Key,int type) { H[++H[0].key]=Key; long x=H[0].key; factor t; while (1) { if (x==1) return 1; if ( Get(H[x],type) >= Get(H[x/2],type) ) return x; t=H[x]; H[x]=H[x/2]; H[x/2]=t; if (type==2) { Pos[ Point[x] ]=x/2; Pos[ Point[x/2] ]=x; long temp=Point[x/2]; Point[x/2]=Point[x]; Point[x]=temp; } x/=2; } } int main(void) { freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); long i,j,x; char s[2]={0}; memset(H1,0,sizeof(H1)); memset(H2,0,sizeof(H2)); for (i=1;i<=N;++i) H1[i].key=i; H1[0].key=N; H2[0].key=0; while ( !feof(stdin) ) { scanf("%ld%s",&x,&s); while (1) { if ( x-H2[1].time>=600 && H2[0].key>0) { factor y=DeleteMin(H2,2); y.time=0; long z=HeapIns(H1,y,1); Pos[y.key]=0; }else break; } if ( !strcmp(s,"+") ) { scanf("\n"); factor y=DeleteMin(H1,1); printf("%ld\n",y.key); y.time=x; Pos[y.key]=HeapIns(H2,y,2); Point[ Pos[y.key] ]=y.key; }else { long y; scanf("%ld\n",&y); if (Pos[y]) { printf("+\n"); H2[ Pos[y] ].time=x; MinHeapfy(H2,Pos[y],2); } else printf("-\n"); } } return 0; }
[编辑] 其他一份解题报告
堆,利用两个不同意义的堆,一个是以编号为key的小根堆,表示空闲的内存;一个是以时间为key的小根堆(存的是根的编号),表示正在用的内存。每次更新正在用的内存堆,如果是写入操作,则把空闲的内存根的时间更新,然后移入正在用的堆,如果是询问操作,那就看它是否在正在用的内存堆里(一个pos[i]数组表示在正在用的内存堆的位置),如果在就把它的时间更新到当前时间,然后从pos[i]向下调整。
sunnywkn的线段树
#include <cstdio> #include <iostream> #include <cstring> #include <string> #include <vector> #include <algorithm> using namespace std; const int MaxN = 30000; const int TT = 600; typedef struct TreeNode * Tree; struct TreeNode { int min, l, r; Tree left, right; }*root; #define L T->left #define R T->right #define M (T->l + T->r >> 1) Tree creat(Tree T, int from, int to) { T = new TreeNode; T->l = from; T->r = to; T->min = 0; if (from != to) { L = creat(L, from, M); R = creat(R, M + 1, to); } return T; } Tree insert(Tree T, int time) { if (T->l == T->r) { printf("%d\n", T->l); T->min = time + TT; return T; } if (time >= L->min) L = insert(L, time); else R = insert(R, time); T->min = min(L->min, R->min); return T; } Tree change(Tree T, int time, int no) { if (T->l == T->r) { if (time < T->min) { puts("+"); T->min = max(T->min, time + TT); } else puts("-"); return T; } if (no <= M) L = change(L, time, no); else R = change(R, time, no); T->min = min(L->min, R->min); return T; } int main() { root = creat(root, 1, MaxN); int time, x; while (scanf("%d", &time) != -1) { char p = ' '; while (p == ' ') p = getchar(); if (p == '+') root = insert(root, time); else { int no; scanf("%d", &no); root = change(root, time, no); } } return 0; }
就是两个操作 1:加入一个数 2:查找并修改一个数 维护一个min域