BZOJ 1588 营业额统计 Splay

来源:互联网 发布:moe破解软件下载 编辑:程序博客网 时间:2024/05/16 23:49
题意:给出序列a,a[i]的贡献为:min(abs(a[i]-a[j])) (j=1..i-1)
n<=3e4,a[i]<=1e6,求出总贡献?

当计算a[i]贡献时 找前面第一个比它大的,最后一个比它小的? 用set维护.

或者建立splay,中序遍历是递增的,把x旋转到根,从根开始找x左子树最右边的,x右子树最左边的即可.

splay模板参考

#include <bits/stdc++.h>using namespace std;const int N=5e5+20;const int inf=0x3f3f3f3f;struct node{int ch[2],f,v;}t[N];int a,tmp,x1,x2,ans;int n,root,tot;void SC(int x,int y,int z){t[x].ch[z]=y;t[y].f=x;}bool d(int x){return t[t[x].f].ch[1]==x;}//x是左孩子还是右孩子. void rot(int x){int y=t[x].f,z=t[y].f,tt=d(x);SC(z,x,d(y));SC(y,t[x].ch[!tt],tt);SC(x,y,!tt);}void splay(int x,int fa){while(t[x].f!=fa){if(t[t[x].f].f==fa){rot(x);break;}if(d(x)==d(t[x].f)){rot(t[x].f);rot(x);}elserot(x),rot(x);}}int get(int x,int s){int tmp=t[x].v;while(x){x=t[x].ch[s];if(x==0||x==n+1)break;tmp=t[x].v;}return tmp;}void insert(int y){if(!root){root=++tot;t[tot].v=y,t[tot].f=0;return;}int x=root,z;while(x){z=x;if(y<t[x].v)x=t[x].ch[0];elsex=t[x].ch[1];}if(y<t[z].v)t[z].ch[0]=++tot;elset[z].ch[1]=++tot;t[tot].v=y,t[tot].f=z;splay(tot,0),root=tot;//}int main(){scanf("%d",&n);scanf("%d",&ans);t[0].v=t[n+1].v=inf;insert(ans);for(int i=2;i<=n;i++){scanf("%d",&a);insert(a);x1=get(t[root].ch[0],1);x2=get(t[root].ch[1],0);int res=min(abs(a-x1),abs(a-x2));ans+=res;}cout<<ans<<endl;return 0;}