题目:http://mail.bashu.cn:8080/bs_oj/showproblem?problem_id=2098
分析:这题貌似有很简便的方法,不过还是可以用SBT来搞的,只要标记一下树里面包含的是宠物还是收养者,如果与现在来的这位一样的话就住下,否者找个相近的一起走了。。。只用到插入,删除,前驱,后继,查找
代码:
#include<cstdio> #include<iostream> #include<cmath> using namespace std; const int mm=111111; int L[mm],R[mm],S[mm],V[mm]; int i,x,y,a,b,n,tt,root,kind,ans,sum; void Right_Rotate(int &t) { int k=L[t]; L[t]=R[k]; R[k]=t; S[k]=S[t]; S[t]=S[L[t]]+S[R[t]]+1; t=k; } void Left_Rotate(int &t) { int k=R[t]; R[t]=L[k]; L[k]=t; S[k]=S[t]; S[t]=S[L[t]]+S[R[t]]+1; t=k; } void maintain(int &t,bool flag) { if(flag) if(S[R[R[t]]]>S[L[t]])Left_Rotate(t); else if(S[L[R[t]]]>S[L[t]]) Right_Rotate(R[t]),Left_Rotate(t); else return; else if(S[L[L[t]]]>S[R[t]])Right_Rotate(t); else if(S[R[L[t]]]>S[R[t]]) Left_Rotate(L[t]),Right_Rotate(t); else return; maintain(L[t],0); maintain(R[t],1); maintain(t,0); maintain(t,1); } void Insert(int &t,int v) { if(t) { ++S[t]; if(v<V[t])Insert(L[t],v); else Insert(R[t],v); maintain(t,v>=V[t]); } else { S[t=++tt]=1; V[t]=v; L[t]=R[t]=0; } } int Delete(int &t,int v) { --S[t]; if(v==V[t]||v<V[t]&&!L[t]||v>V[t]&&!R[t]) { int tmp=V[t]; if(!L[t]||!R[t])t=L[t]+R[t]; else V[t]=Delete(L[t],V[t]+1); return tmp; } else if(v<V[t])return Delete(L[t],v); else return Delete(R[t],v); } int Find(int t,int v) { while(t&&v!=V[t]) t=v<V[t]?Find(L[t],v):Find(R[t],v); return t; } int Rank(int t,int v) { if(!t)return 1; if(v<=V[t])return Rank(L[t],v); else return S[L[t]]+1+Rank(R[t],v); } int Select(int t,int k) { if(k==S[L[t]]+1)return V[t]; if(k<=S[L[t]])return Select(L[t],k); else return Select(R[t],k-1-S[L[t]]); } int Pred(int t,int v) { if(!t)return v; if(v<=V[t])return Pred(L[t],v); else { int tmp=Pred(R[t],v); return v==tmp?V[t]:tmp; } } int Succ(int t,int v) { if(!t)return v; if(v>=V[t])return Succ(R[t],v); else { int tmp=Succ(L[t],v); return v==tmp?V[t]:tmp; } } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d",&n); sum=ans=tt=root=kind=S[0]=0; for(i=0;i<n;++i) { scanf("%d%d",&a,&b); if(!sum||a==kind)kind=a,Insert(root,b),++sum; else { if(Find(root,b))Delete(root,b),--sum; else { x=Pred(root,b); y=Succ(root,b); if(x==b||y==b)x=x+y-b; else if(b-x>y-b)x=y; ans+=fabs(b-x),Delete(root,x),--sum; if(ans>=1000000)ans%=1000000; } } } printf("%d\n",ans); return 0; }
这题用splay来解还是比较麻烦的,因为要删掉节点,每次都把节点的前驱转到根,把后继转到根的子节点,这样要删的点就是根的右儿子的左儿子,直接删掉就行了
开始熟练起来了^_^
代码:
#include<cstdio> #include<iostream> #include<cmath> using namespace std; const int mm=88888; struct splaytree { int c[mm][2],p[mm],s[mm],v[mm]; int id,size,root,flag,ans; void rotate(int x,int f) { int y=p[x]; c[y][!f]=c[x][f]; p[c[x][f]]=y; p[x]=p[y]; if(p[x])c[p[y]][c[p[y]][1]==y]=x; c[x][f]=y; p[y]=x; updata(y); } void splay(int x,int goal) { while(p[x]!=goal) if(p[p[x]]==goal)rotate(x,c[p[x]][0]==x); else { int y=p[x],f=(c[p[y]][0]==y); if(c[y][f]==x)rotate(x,!f); else rotate(y,f); rotate(x,f); } updata(x); if(!goal)root=x; } void select(int k,int goal) { int x=root; while(s[c[x][0]]+1!=k) { if(k<s[c[x][0]]+1)x=c[x][0]; else k-=(s[c[x][0]]+1),x=c[x][1]; } splay(x,goal); } void insert(int a) { int x=root; ++size; while(c[x][v[x]<a])x=c[x][v[x]<a]; newnode(c[x][v[x]<a],a); p[id]=x; splay(id,0); } void remove(int x) { splay(x,0); int y=s[c[x][0]]; select(y,0); select(y+2,root); c[c[root][1]][0]=0; updata(c[root][1]); updata(root); --size; } void updata(int x) { s[x]=1+s[c[x][0]]+s[c[x][1]]; } void newnode(int &x,int a) { x=++id; p[x]=c[x][0]=c[x][1]=0; s[x]=1; v[x]=a; } void prepare() { ans=id=root=size=0; p[0]=c[0][0]=c[0][1]=v[0]=0; newnode(root,-1000000000); newnode(c[root][1],1000000000); p[id]=root; s[root]=2; } int find(int a) { int x=root,ret,s=1000000000; while(x) { if(v[x]==a)return x; if(v[x]<a) { if(a-v[x]<=s)s=a-v[x],ret=x; } else { if(v[x]-a<s)s=v[x]-a,ret=x; } x=c[x][v[x]<a]; } return ret; } void work() { int a,b,x; scanf("%d%d",&a,&b); if(a==flag||size==0)insert(b),flag=a; else { x=find(b); ans+=(int)fabs(b-v[x]); if(ans>=1000000)ans%=1000000; remove(x); } } }spt; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n; scanf("%d",&n); spt.prepare(); while(n--)spt.work(); printf("%d\n",spt.ans); return 0; }