【bzoj1208】宠物收养所——treap
第二道treap题,码完之后总是RE……查了两个多小时的错,对拍了三四份代码啊啊啊
刚开始发现if(tree[k].l*tree[k].r==0)k=tree[k].l+tree[k].r;这一句写错了,但改完还是WA或RE……
于是又找了接近两个小时的错啊啊啊,终于发现是左旋操作中的一个t打成了k,枉我之前还一直以为是del或者get_big写错了呢
还是不够细心啊
好了,言归正传。
这道题由于题目说“同一时间呆在收养所中的,要么全是宠物,要么全是领养者”,那么就可以建一棵treap树(用一个变量ty储存当前树类型,即1或0),与当前树类型相同就加入该节点,不同就对比该值与前驱值差和后继值差的绝对值,取较小的一个(若相同则选前驱),接着ans加上该值(记得要取余mod!),然后del前驱或后继,最后得到的ans即为答案。
具体细节看代码。
#include<cstdio> #include<cstdlib> #include<iostream> const int mod=1000000; using namespace std; int n,root=0,ty,ans=0,size=0,tt,pp,a,b; struct point { int v,l,rnd,r; }tree[100002]; void lturn(int &k) { int t=tree[k].r; tree[k].r=tree[t].l; tree[t].l=k; k=t; } void rturn(int &k) { int t=tree[k].l; tree[k].l=tree[t].r; tree[t].r=k; k=t; } void insert(int &k,int x) { if(k==0) { size++;k=size; tree[k].l=tree[k].r=0; tree[k].v=x;tree[k].rnd=rand(); return; } if(x>tree[k].v) { insert(tree[k].r,x); if(tree[tree[k].r].rnd<tree[k].rnd)lturn(k); } else { insert(tree[k].l,x); if(tree[tree[k].l].rnd<tree[k].rnd)rturn(k); } } void del(int &k,int x) { if(k==0)return; if(tree[k].v==x) { if(tree[k].l*tree[k].r==0)k=tree[k].l+tree[k].r; else if(tree[tree[k].l].rnd<tree[tree[k].r].rnd)rturn(k),del(k,x); else lturn(k),del(k,x); } else if(tree[k].v<x)del(tree[k].r,x); else del(tree[k].l,x); } void get_big(int k,int x) { if(k==0)return; if(tree[k].v<=x) { tt=k;get_big(tree[k].r,x); } else get_big(tree[k].l,x); } void get_small(int k,int x) { if(k==0){return;} if(tree[k].v>x) { pp=k;get_small(tree[k].l,x); } else get_small(tree[k].r,x); } int main() { int num=0; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d %d",&a,&b); if(!num){size=0;root=0,insert(root,b),ty=a,num++;} else if(a==ty){ insert(root,b); num++; } else { tt=0;get_big(root,b); pp=0;get_small(root,b); if(!pp||(tt&&tree[tt].v&&b-tree[tt].v<=tree[pp].v-b)){ans=(ans+b-tree[tt].v)%mod;del(root,tree[tt].v);} else {ans=(ans+tree[pp].v-b)%mod;del(root,tree[pp].v);} num--; } } printf("%d",ans); return 0; }