首页 > 代码库 > POJ 3481 Double Queue 堆修改标记
POJ 3481 Double Queue 堆修改标记
Enemy Double Queue!
题目大意:维护一种数据结构,支持以下操作:
1.插入一个值
2.查询最大值并删除
3.查询最小值并删除
元素的值<=1000W
这数据结构一看就是堆。。。不过堆结构不能同时维护最大值和最小值,于是我们开两个堆,一个大根堆,一个小根堆
其中一堆删除时,另一堆也要删除相应元素
于是删除的话有两种方法
1.映射 1000W开数组映射妥妥MLE 于是我们在两个堆之间互相映射
不太好写 pair里开自己的指针会报错,于是只能开了void* 不过速度还是很可观的
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 using namespace std; typedef pair<int,void*> abcd; struct small_root_heap{ abcd heap[M]; int top; void push_up(int t) { while(t>1&&heap[t]<heap[t>>1]) swap(heap[t],heap[t>>1]),swap( ((abcd*)heap[t].second)->second , ((abcd*)heap[t>>1].second)->second ),t>>=1; } void push_down(int t) { t<<=1; while(t<=top) { if(heap[t]>heap[t+1]&&t<top) t++; if(heap[t]<heap[t>>1]) swap(heap[t],heap[t>>1]),swap( ((abcd*)heap[t].second)->second , ((abcd*)heap[t>>1].second)->second ),t<<=1; else break; } } void insert(int x) { heap[++top].first=x; push_up(top); } void pop() { heap[1]=heap[top--]; ((abcd*)heap[1].second)->second=&heap[1]; push_down(1); } void del(abcd *x) { int t=x-heap; heap[t]=heap[top--]; ((abcd*)heap[t].second)->second=&heap[t]; push_down(t); push_up(t); } }big,small; int map[10001000]; void insert(int x) { big.heap[big.top+1].second=&small.heap[small.top+1]; small.heap[small.top+1].second=&big.heap[big.top+1]; big.insert(-x); small.insert(x); } int getmax() { if(!big.top) return 0; int re=map[-big.heap[1].first]; small.del((abcd*)big.heap[1].second); big.pop(); return re; } int getmin() { if(!small.top) return 0; int re=map[small.heap[1].first]; big.del((abcd*)small.heap[1].second); small.pop(); return re; } int main() { int p,x,y; while(scanf("%d",&p),p) { if(p==1) scanf("%d%d",&x,&y),map[y]=x,insert(y); else if(p==2) printf("%d\n", getmax() ); else printf("%d\n", getmin() ); } }
另外一种方法是我原创的,叫做堆修改标记
思想和堆优化SPFA十分类似 就是延时删除
开一个Delmark数组,删除的时候Delmark[x]++,需要取堆顶的时候判断堆顶有没有delmark,如果有就弹掉
insert的时候如果有标记同理
但是为什么数组映射就会MLE 开数组打标记就不会呢? 因为标记可以开成char。。。。
这题保证元素不重复 所以Delmark顶多是1 否则必死无疑 最后空间开了59256K 真是险些MLE..
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int map[10001000]; int n,m; struct Heap_Changing_Lazy{ int heap[100100],top; char delmark[10001000]; void insert(int x) { if(delmark[x]) { delmark[x]--; return ; } heap[++top]=x; int t=top; while(t>1&&heap[t]>heap[t>>1]) swap(heap[t],heap[t>>1]),t>>=1; } //插入,如果有delmark的话直接delmark[x]-- void pop() { if(!top) return ; heap[1]=heap[top]; heap[top--]=0; int t=2; while(t<=top) { if(heap[t]<heap[t+1]&&t<top) t++; if(heap[t]>heap[t>>1]) swap(heap[t],heap[t>>1]),t<<=1; else break; } }//弹顶 int begin(){ int t; while(delmark[heap[1]]) delmark[heap[1]]--,pop();//把有删除标记的堆顶全部删除 t=heap[1]; return t; } }Maxheap,Minheap; int main() { int p,x,y,t; while(scanf("%d",&p),p) { switch(p) { case 1:scanf("%d%d",&x,&y),map[y]=x,Maxheap.insert(y),Minheap.insert(10000001-y);break; case 2:t=Maxheap.begin(),Maxheap.pop(),printf("%d\n",map[t]),Minheap.delmark[10000001-t]++;break; case 3:t=10000001-Minheap.begin(),Minheap.pop(),printf("%d\n",map[t]),Maxheap.delmark[t]++;break; } } }
Discuss里各种平衡树,以及各种写挂的平衡树。。。
还是堆强大啊
POJ 3481 Double Queue 堆修改标记
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。