bzoj 1588 营业额统计
题目大意:
一些数,依次加进去,每次加进去一个数a之前 在已经加进去的数找一个数k
使|k-a|最小,求这个最小值
思路:
用splay维护已经加进去的数
每次查询时查询它的前驱与后继 求出最小值
并把它splay到根节点上去(使它的前驱和后继分别在它的左子树和右子树里)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 100100 12 #define MOD 1000000007 13 using namespace std; 14 inline int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 18 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 int ch[MAXN][2],fa[MAXN],sz,val[MAXN],rt,same; 22 int which(int x) {return x==ch[fa[x]][1];} 23 int find_pre() 24 { 25 int pos=ch[rt][0]; 26 while(ch[pos][1]) pos=ch[pos][1]; 27 return pos; 28 } 29 int find_sub() 30 { 31 int pos=ch[rt][1]; 32 while(ch[pos][0]) pos=ch[pos][0]; 33 return pos; 34 } 35 void rotate(int pos) 36 { 37 int f=fa[pos],ff=fa[f],k=which(pos); 38 ch[f][k]=ch[pos][k^1],fa[ch[f][k]]=f,fa[f]=pos,ch[pos][k^1]=f,fa[pos]=ff; 39 if(ff) ch[ff][ch[ff][1]==f]=pos; 40 } 41 void splay(int x) 42 { 43 for(int f;f=fa[x];rotate(x)) 44 if(fa[f]) rotate((which(x)==which(f)?f:x)); 45 rt=x; 46 } 47 void Insert(int x) 48 { 49 int pos=rt,f=0; 50 while(1) 51 { 52 if(val[pos]==x) {splay(pos);same=1;return ;} 53 f=pos,pos=ch[pos][x>val[pos]]; 54 if(!pos) 55 { 56 ch[++sz][0]=ch[sz][1]=0,fa[sz]=f,val[sz]=x,ch[f][x>val[f]]=sz; 57 splay(sz);return ; 58 } 59 } 60 } 61 void insert(int x) 62 { 63 if(!rt) {val[++sz]=x,ch[sz][0]=ch[sz][1]=fa[sz]=0,rt=sz;return;} 64 Insert(x); 65 } 66 int main() 67 { 68 int T=read(),x,pre,tmp,sub,ans=0; 69 while(T--) 70 { 71 x=read(),tmp=inf,same=0; 72 insert(x); 73 if(same) continue; 74 pre=find_pre(),sub=find_sub(); 75 if(pre) tmp=min(tmp,x-val[pre]); 76 if(sub) tmp=min(tmp,val[sub]-x); 77 ans+=(tmp==inf?x:tmp); 78 } 79 printf("%d",ans); 80 }