[BZOJ 1588] HNOI 2002 营业额统计

来源:互联网 发布:h3c路由器端口映射 sql 编辑:程序博客网 时间:2024/05/20 19:15

首先!特别强调!这题非常坑!比如第一个点!n=32767,但是只给了你32766个值,最后一个当成0来做!就这问题笔者调了一个小时才发现!而且网上的题解中都没有提到!请各位猿们在写代码时特别注意!!!

今天刚刚学了Splay,就拿这题练手了。

关于Splay,建议大家去看国家集训队论文2004年杨思雨的《伸展树的基本操作与应用》,笔者觉得很适合初学者看。

那么对于本题,目的是对于每个数找出之前的数中和它相差最小的数。

每读入一个数就插入树中,经过Splay操作后查找其前趋和后继并进行比较,计算答案。

讲义中虽然没有提到,但是直接Splay的话要判断是Zig还是Zag,但是Splay操作实际代码实现时非常简洁巧妙,希望各位猿们慢慢的看和领悟,拿着草稿纸自己画画写写,当你像笔者当时一样终于看懂时,你会发现这个方法实在是太巧妙了,平衡树往往一两百行的程序,但是这题笔者只写了70行。

#include <stdio.h>#include <algorithm>#include <string.h>#include <iostream>using namespace std;#define read freopen("1588.in","r",stdin)#define write freopen("1588.out","w",stdout)#define inf (1<<30)const int maxn=100005;int n,k,pre[maxn],data[maxn],ch[maxn][2],tot,ans,root;//kind==1 Zig  kind==0 Zagvoid rotate(int x,int kind){int y=pre[x];ch[y][!kind]=ch[x][kind];pre[ch[x][kind]]=y;if (pre[y])   ch[pre[y]][ch[pre[y]][1]==y]=x;pre[x]=pre[y];ch[x][kind]=y;pre[y]=x;}void splay(int t){while (pre[t]!=0)if (pre[pre[t]]==0) rotate(t,ch[pre[t]][0]==t);else{int y=pre[t];bool kind=ch[pre[y]][1]==y;if (ch[y][kind]==t)   rotate(t,!kind),rotate(t,!kind);   else    rotate(t,kind),rotate(t,!kind);    }   root=t;}void ins(int k){//伸展树的查找、插入和查找树是一样的 int now;for (now=root;ch[now][data[now]<k];now=ch[now][data[now]<k]); data[++tot]=k;ch[now][data[now]<k]=tot;pre[tot]=now;splay(tot); }int get_pre(){int now=ch[root][0];if (!now) return inf;//特判是否有左/右子树 for (;ch[now][1];now=ch[now][1]);return k-data[now];}int get_suf(){int now=ch[root][1];if (!now) return inf;//同上 for (;ch[now][0];now=ch[now][0]);return data[now]-k;}int main(){#ifndef ONLINE_JUDGEread;write;#endifcin>>n;tot=0;for (int i=1;i<=n;i++){if (scanf("%d",&k)==EOF) k=0;ins(k);if (i==1) {ans+=k;continue;}ans+=min(get_pre(),get_suf());}cout<<ans<<endl;return 0;}


 

0 0
原创粉丝点击