1 条题解
-
0Guest LV 0
-
0
发表域里面的第一份题解:
此题可以用线段树做(不知道可不可以用平衡树)其实我看到题的第一想法是对内存分块,每一次暴力寻找合法的块。
但是并不可行,为什么呢?因为我们只能维护块的使用,不能维护块中每一个元素的使用,这会导致如果释放已经释放过的内存,我们会算重。那么来看看线段树怎么做。
线段树维护以下内容:
size当前段所有可用内存总长度,
sum当前段最长的一段内存长度,
lsum当前段从左向右能延伸的最长的内存长度,
rsum当前段从右向左能延伸的最长的内存长度,
pos每一段内存的从右向左的能延伸的长度的开始位置。从左向右可以找到位置就是left,然而从中间断开就不行了,因此还要维护这个。维护的信息就这样了,那么修改就简单了。
这里要注意一下!
修改的时候懒标记清空一定要清为-1!!询问怎么办呢?
拿到当前这么一段区间,先看左半段能否满足需求,如果可以就进入左半段递归。
左半段不能满足,再看看中间拼起来能否满足,如果可以直接返回左边的pos。
如果仍不能满足,看看右半段能否满足需求,如果可以就进入右半段递归。
如果都不能,返回-1。此题完美解决
#include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std; inline const int Get_Int() { int num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; } const int maxn=500005; struct Tree { int left,right,lazy; int size,sum,leftsum,rightsum; //size记录总共的空段 sum记录最长空段 int pos; //pos保存当前段如果从中间分开,左边的开始处坐标 Tree() {} Tree(int l,int r):left(l),right(r) { lazy=-1; size=sum=leftsum=rightsum=pos=0; } }; struct Segment_Tree { Tree tree[maxn*4]; #define ls (index*2) #define rs (index*2+1) void build(int index,int Left,int Right) { tree[index]=Tree(Left,Right); if(Left==Right)return; int mid=(Left+Right)/2; build(ls,Left,mid); build(rs,mid+1,Right); } void push_up(int index) { tree[index].size=tree[ls].size+tree[rs].size; if(ls)tree[index].leftsum=tree[ls].leftsum; if(tree[ls].leftsum==tree[ls].right-tree[ls].left+1)tree[index].leftsum=max(tree[index].leftsum,tree[ls].size+tree[rs].leftsum); //左儿子内存全为空才能接右边 if(rs) { tree[index].rightsum=tree[rs].rightsum; tree[index].pos=tree[rs].pos; } if(tree[rs].rightsum==tree[rs].right-tree[rs].left+1) { //右儿子内存全为空才能接右边 tree[index].rightsum=max(tree[index].rightsum,tree[ls].rightsum+tree[rs].size); tree[index].pos=tree[ls].pos; //接过来后改变起始位置 } tree[index].sum=max(tree[ls].sum,max(tree[rs].sum,tree[ls].rightsum+tree[rs].leftsum)); } void modify(int index,int data) { if(!index)return; tree[index].lazy=data; tree[index].size=tree[index].leftsum=tree[index].rightsum=tree[index].sum=data?tree[index].right-tree[index].left+1:0; tree[index].pos=data?tree[index].left:(tree[index].right+1); } void push_down(int index) { if(tree[index].lazy==-1)return; modify(ls,tree[index].lazy); modify(rs,tree[index].lazy); tree[index].lazy=-1; } void modify(int index,int Left,int Right,int val) { if(Left>tree[index].right||Right<tree[index].left)return; if(Left<=tree[index].left&&Right>=tree[index].right) { modify(index,val); return; } push_down(index); modify(ls,Left,Right,val); modify(rs,Left,Right,val); push_up(index); } int query(int index,int len) { if(tree[index].left==tree[index].right)return tree[index].left; push_down(index); if(tree[ls].sum>=len)return query(ls,len); //左边最长可用 访问左边 if(tree[ls].rightsum+tree[rs].leftsum>=len)return tree[ls].pos; //左边右边拼凑可用 返回 if(tree[rs].sum>=len)return query(rs,len); //右边最长可用 访问右边 return -1; //没有一个可用 } } st; int len; char order; int main() { ios::sync_with_stdio(false); cin>>len; st.build(1,1,len); st.modify(1,1,len,1); while(cin>>order) { if(order=='Q') { int x; cin>>x; if(x<=0)puts("Ivalid Request"); else { int pos=st.query(1,x); if(pos!=-1)st.modify(1,pos,pos+x-1,0); //占用 printf("%d\n",pos); } } else { int Left,Right; cin>>Left>>Right; if(Left>Right||Left<=0||Right<=0)puts("Ivalid Request"); else { st.modify(1,Left,Right,1); printf("%d\n",st.tree[1].size); } } } return 0; }
- 1