【bzoj1208 宠物收养所】
题目描述:
最近,阿Q开了一间宠物收养所。收养所提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物。每个领养者都希望领养到自己满意的宠物,阿Q根据领养者的要求通过他自己发明的一个特殊的公式,得出该领养者希望领养的宠物的特点值a(a是一个正整数,a<2^31),而他也给每个处在收养所的宠物一个特点值。这样他就能够很方便的处理整个领养宠物的过程了,宠物收养所总是会有两种情况发生:被遗弃的宠物过多或者是想要收养宠物的人太多,而宠物太少。 1. 被遗弃的宠物过多时,假若到来一个领养者,这个领养者希望领养的宠物的特点值为a,那么它将会领养一只目前未被领养的宠物中特点值最接近a的一只宠物。(任何两只宠物的特点值都不可能是相同的,任何两个领养者的希望领养宠物的特点值也不可能是一样的)如果有两只满足要求的宠物,即存在两只宠物他们的特点值分别为a-b和a+b,那么领养者将会领养特点值为a-b的那只宠物。 2. 收养宠物的人过多,假若到来一只被收养的宠物,那么哪个领养者能够领养它呢?能够领养它的领养者,是那个希望被领养宠物的特点值最接近该宠物特点值的领养者,如果该宠物的特点值为a,存在两个领养者他们希望领养宠物的特点值分别为a-b和a+b,那么特点值为a-b的那个领养者将成功领养该宠物。 一个领养者领养了一个特点值为a的宠物,而它本身希望领养的宠物的特点值为b,那么这个领养者的不满意程度为abs(a-b)。【任务描述】你得到了一年当中,领养者和被收养宠物到来收养所的情况,希望你计算所有收养了宠物的领养者的不满意程度的总和。这一年初始时,收养所里面既没有宠物,也没有领养者。
输入格式:
第一行为一个正整数n,n<=80000,表示一年当中来到收养所的宠物和领养者的总数。接下来的n行,按到来时间的先后顺序描述了一年当中来到收养所的宠物和领养者的情况。每行有两个正整数a, b,其中a=0表示宠物,a=1表示领养者,b表示宠物的特点值或是领养者希望领养宠物的特点值。(同一时间呆在收养所中的,要么全是宠物,要么全是领养者,这些宠物和领养者的个数不会超过10000个)
输出格式:
仅有一个正整数,表示一年当中所有收养了宠物的领养者的不满意程度的总和mod 1000000以后的结果。
输入样例:
0 2
0 4
1 3
1 2
1 5
输出样例:
题解:
splay第二题,代码稍微好看了点吧。(调了一个下午)
维护一个splay,kind为这棵树维护的是宠物或者领养者,那么对于一样的群体就是插入操作,否则即为询问。每此给你一个数找前驱后继,直接二叉树遍历。然后把这个宠物或者领养者从splay中删除。如何删除?首先把这个点splay到root,把左子树与root断开(fa[ch[root][0]]=-1),然后找到左子树中最大的节点x,调至该子树的root(splay(x)),最后把原树的右子树成为左子树的右子树(ch[x][1]=ch[root][1])。
写代码的几个错误。ch[x][0/1]存的是点的编号。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cstdio> 5 int fa[80005],ch[80005][3],root,sum[80005],cnt; 6 int poss,posp,pren,sucn; 7 inline void rotate(int x,int k) 8 { 9 int y,z;y=fa[x],z=fa[y]; 10 ch[y][1-k]=ch[x][k];if(ch[x][k]!=-1) fa[ch[x][k]]=y; 11 fa[x]=z;if(z!=-1) ch[z][ch[z][1]==y]=x; 12 fa[y]=x;ch[x][k]=y; 13 } 14 inline void splay(int x) 15 { 16 while(fa[x]!=-1) 17 { 18 int y,z;y=fa[x],z=fa[y]; 19 if(z==-1) rotate(x,ch[y][1]!=x); 20 else 21 { 22 if(ch[z][0]==y) 23 { 24 if(ch[y][0]==x) rotate(y,1),rotate(x,1); 25 else rotate(x,0),rotate(x,1); 26 } 27 else 28 { 29 if(ch[y][0]==x) rotate(x,1),rotate(x,0); 30 else rotate(y,0),rotate(x,0); 31 } 32 } 33 } 34 root=x; 35 } 36 inline void build(int x,int f) 37 { 38 sum[++cnt]=x; 39 fa[cnt]=f; 40 ch[cnt][0]=ch[cnt][1]=-1; 41 } 42 inline void insert(int x) 43 { 44 if(root==-1) 45 { 46 build(x,-1);root=cnt; 47 return; 48 } 49 int y=root; 50 while(1) 51 { 52 if(x>sum[y]) 53 { 54 if(ch[y][1]==-1) 55 { 56 build(x,y); 57 ch[y][1]=cnt; 58 return; 59 } 60 else y=ch[y][1]; 61 } 62 else 63 { 64 if(ch[y][0]==-1) 65 { 66 build(x,y); 67 ch[y][0]=cnt; 68 return; 69 } 70 else y=ch[y][0]; 71 } 72 } 73 } 74 inline void del(int x) 75 { 76 splay(x); 77 if(ch[x][0]==-1 && ch[x][1]==-1) 78 { 79 root=-1; 80 return; 81 } 82 if(ch[x][0]==-1) 83 { 84 root=ch[x][1]; 85 fa[ch[x][1]]=-1; 86 return; 87 } 88 if(ch[x][1]==-1) 89 { 90 root=ch[x][0]; 91 fa[ch[x][0]]=-1; 92 return; 93 } 94 int now=ch[x][0]; 95 while(ch[now][1]!=-1) now=ch[now][1]; 96 fa[ch[x][0]]=-1; 97 splay(now); 98 ch[now][1]=ch[x][1];fa[ch[x][1]]=now; 99 root=now; 100 } 101 inline void find_pre(int x) 102 { 103 int y=root;posp=-1,pren=1e9+7; 104 while(1) 105 { 106 if(y==-1) return; 107 if(sum[y]<x && (x-sum[y])<pren) 108 { 109 pren=x-sum[y]; 110 posp=y; 111 } 112 if(sum[y]<x) y=ch[y][1]; 113 else y=ch[y][0]; 114 } 115 } 116 inline void find_suc(int x) 117 { 118 int y=root;poss=-1,sucn=1e9+7; 119 while(1) 120 { 121 if(y==-1) return; 122 if(x<sum[y] && sum[y]-x<sucn) 123 { 124 sucn=sum[y]-x; 125 poss=y; 126 } 127 if(x<sum[y]) y=ch[y][0]; 128 else y=ch[y][1]; 129 } 130 } 131 int main() 132 { 133 int n,kind,t,x,ans=0; 134 scanf("%d",&n); 135 scanf("%d%d",&kind,&x); 136 build(x,-1);root=cnt; 137 for(int i=1;i<n;i++) 138 { 139 scanf("%d%d",&t,&x); 140 if(root==-1) 141 { 142 kind=t; 143 build(x,-1);root=cnt; 144 } 145 else 146 { 147 if(t==kind) 148 { 149 insert(x); 150 splay(cnt); 151 } 152 else 153 { 154 find_pre(x);find_suc(x); 155 int mn=1e9+7,pos=-1; 156 if(posp!=-1 && pren<mn) 157 { 158 mn=pren; 159 pos=posp; 160 } 161 if(poss!=-1 && sucn<mn) 162 { 163 mn=sucn; 164 pos=poss; 165 } 166 ans=(ans+mn)%1000000; 167 del(pos); 168 } 169 } 170 } 171 printf("%d",ans); 172 return 0; 173 }