BZOJ1208_宠物收养所_KEY
平衡树的题。
因为题目给出条件(其实自己也知道):同一时间呆在收养所中的,要么全是宠物,要么全是领养者,这些宠物和领养者的个数不会超过10000个。
所以只要维护一颗平衡树,它的里面要不全是人,要不全是宠物。
找到人的前驱后继比较。
code:
/************************************************************** Problem: 1208 User: yekehe Language: C++ Result: Accepted Time:180 ms Memory:2388 kb ****************************************************************/ #include <cstdio> #include <cstdlib> using namespace std; int read() { char c;while(c=getchar(),c<'0'||c>'9'); int x=c-'0';while(c=getchar(),c>='0'&&c<='9')x=x*10+c-'0'; return x; } int N,now,root,cnt,dist; int tr[80005][2],v[80005],r[80005],f[80005]; void clear(int x){f[x]=tr[x][0]=tr[x][1]=r[x]=v[x]=0;} void up(int x){f[x]=f[tr[x][0]]+f[tr[x][1]];} int abs(int x){return x>0?x:-x;} void rotate(int &x,int o) { int k=tr[x][o]; tr[x][o]=tr[k][o^1]; tr[k][o^1]=x; f[k]=f[x]; up(x); x=k; } void insert(int &x,int val) { if(!x){ x=++cnt; v[x]=val; r[x]=rand(); f[x]++; return ; } int to=val>v[x]; insert(tr[x][to],val); if(r[x]>r[tr[x][to]])rotate(x,to); return ; } void del(int &x,int val) { if(v[x]==val){ if(!(tr[x][0]+tr[x][1])){ clear(x);x=0; return ; } if(!(tr[x][0]*tr[x][1])){ int w=tr[x][0]+tr[x][1]; clear(x);x=w; return ; } rotate(x,0); del(x,val); return ; } f[x]--; int to=val>v[x]; del(tr[x][to],val); up(x); return ; } void pre(int x,int val)//前驱 { if(!x)return ; if(v[x]>=val)pre(tr[x][0],val); else{ dist=x; pre(tr[x][1],val); } } void bac(int x,int val)//后继 { if(!x)return ; if(v[x]<=val)bac(tr[x][1],val); else{ dist=x; bac(tr[x][0],val); } } int main() { srand(23333); N=read(); int i,ans=0,o1,o2,tot=0; for(i=1;i<=N;i++){ int x=read(),y=read(); if(!tot){insert(root,y),now=x;tot++;continue;} if(now==x)insert(root,y),tot++; else{ dist=0;pre(root,y);o1=dist; dist=0;bac(root,y);o2=dist; if(!o1&&!o2)continue; int k1=o1?y-v[o1]:2e9,k2=o2?v[o2]-y:2e9; dist=k1>k2?o2:o1;//找较接近的值 ans=(ans+abs(v[dist]-y))%1000000; del(root,v[dist]); tot--; } } printf("%d",ans); return 0; }