【Splay】BZOJ 1588 [HNOI2002]营业额统计
2014-08-13 14:34
501 查看
用splay的基本操作Find_pre和Find_succ来实现
</pre><pre name="code" class="cpp">
#include<cstdio> #include<iostream> #include<cmath> using namespace std; const int maxint = 214748364; const int MAX_N = 40000; //0表示空结点NULL struct Node { int key,num,fa; int son[2]; }Tree[MAX_N]; int root=0,tot=0; int n; //c=0 为左旋,c=1 为右旋 void Rotate(int x,int c){ int y = Tree[x].fa; Tree[y].son[!c] = Tree[x].son[c]; if(Tree[x].son[c]) Tree[Tree[x].son[c]].fa = y; Tree[x].fa = Tree[y].fa; if(Tree[y].fa) { /*if(Tree[y].fa.son[0] == y) Tree[y].fa.son[0] = x; else Tree[y].fa.son[1] = x;*/ Tree[Tree[y].fa].son[Tree[Tree[y].fa].son[1]==y] = x; } Tree[y].fa = x; Tree[x].son[c] = y; } void Splay(int x, int f){ while(Tree[x].fa != f) { if(Tree[Tree[x].fa].fa == f) Rotate(x,Tree[Tree[x].fa].son[0]==x); else { int y = Tree[x].fa; int kind = Tree[Tree[y].fa].son[1] == y; //kind=0 表示y为其父亲的左儿子,kind=1 表示y为右儿子 if(Tree[y].son[kind] == x) Rotate(y,!kind) , Rotate(x,!kind); else Rotate(x,kind) , Rotate(x,!kind); } } if(f==0) root = x; } void Insert(int val,int x){ //根节点为0,即树为空 if(!x){ root = ++tot; Tree[tot].key = val;Tree[tot].fa = 0;Tree[tot].num = 1; return ; } if(Tree[x].key == val) { Tree[x].num++; Splay(x,0);//将当前结点旋转到NULL下,即成为根节点 return; } //要插入的结点为空 if(!Tree[x].son[val>Tree[x].key]){ Tree[x].son[val>Tree[x].key] = ++tot; Tree[tot].fa = x;Tree[tot].key = val; Tree[tot].num = 1; Splay(tot,0); } else Insert(val,Tree[x].son[val>Tree[x].key]); } int Find_pre(int x){ if(Tree[x].num>1) return Tree[x].key; int Next = Tree[x].son[0]; if(!Next) return maxint; //没有前驱 while(Tree[Next].son[1]) Next = Tree[Next].son[1]; return Tree[Next].key; } int Find_succ(int x){ if(Tree[x].num>1) return Tree[x].key; int Next=Tree[x].son[1]; if(!Next) return maxint;//没有后继 while(Tree[Next].son[0]) Next = Tree[Next].son[0]; return Tree[Next].key; } void middle_order(int x) { if(Tree[x].son[0])middle_order(Tree[x].son[0]); for(int i=1;i<=Tree[x].num;i++)printf("%d ",Tree[x].key); if(Tree[x].son[1])middle_order(Tree[x].son[1]); } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); scanf("%d",&n); int ans=0; for(int i=1;i<=n;i++) { int val=0; scanf("%d",&val); Insert(val,root); if(i==1) { ans+=val; continue; } int Pred = Find_pre(root), Succ = Find_succ(root); ans += min(fabs(Pred-val), fabs(Succ-val)); } printf("%d\n",ans); return 0; }
或者使用c++的STL中的multiset来实现 这里发现如果先lower_bound来找答案的话会超时,而改为先插入当前元素,再使用find来计算答案就不会超时
/*happywu * 2014.8.12 * bzoj 1588 */ #include<cstdio> #include<iostream> #include<set> #include<algorithm> using namespace std; multiset<int> q; multiset<int> ::iterator it; int n; int x; /*int main()//超时 { freopen("a.in","r",stdin); scanf("%d",&n); multiset<long long >::iterator tmp; long long ans=0; for(int i=1;i<=n;i++) { scanf("%lld",&x); if(i==1){ ans=x; q.insert(x); continue; } multiset<long long >::iterator it=lower_bound(q.begin(),q.end(),x); if(it==q.end()) { it--; ans+=x-*it; it++; } else { if(it!=q.begin()) { long long k1=*it-x; it--; long long k2=x-*it; ans+=min(k1,k2); } else { ans+=*it-x; } } q.insert(x); } printf("%lld\n",ans); return 0; }*/ int main() { //freopen("a.in","r",stdin); scanf("%d",&n); int ans=0; for(int i=1;i<=n;i++) { if(scanf("%d",&x)==EOF)x=0; //输入数据有问题 q.insert(x); if(i==1) ans+=x; else{ it=q.find(x); int b=1<<30; if(it!=q.begin()) it--,b=x-(*it),it++; it++; if(it!=q.end()) b=min(b,(*it)-x); ans+=b; } } printf("%d\n",ans); return 0; }
此题还可以用双向链表来实现 , 具体可见《基本数据结构在信息学竞赛中的应用》
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int INF=1<<31-1; const int maxn=1000000+10; struct Node { int key,idx; bool operator<(const Node&b) { if(key<b.key)return 1; return 0; } }a[maxn]; int c[maxn],pre[maxn],nex[maxn]; bool cmp(const Node&a,const Node&b) { if(a.key<b.key)return 1; return 0; } inline void Erase(int i) { nex[pre[c[i]]]=nex[c[i]]; pre[nex[c[i]]]=pre[c[i]]; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i].key); a[i].idx=i; } a[0].key=a[n+1].key=INF; a[0].idx=INF;a[n+1].idx=n+1; sort(a+1,a+n+1,cmp); for(int i=0;i<=n+1;i++) c[a[i].idx]=i; for(int i=1;i<=n;i++) { nex[i]=i+1; pre[i]=i-1; } int ans=0; for(int i=n;i>=2;i--) { ans+=min(abs(a[nex[c[i]]].key-a[c[i]].key),abs(a[pre[c[i]]].key-a[c[i]].key)); Erase(i); } printf("%d\n",ans+a[c[1]].key); return 0; }
下面同样是双向链表,更加的简洁
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int INF=1<<31-1; const int maxn=1000000+10; int a[maxn],id[maxn],pre[maxn],nex[maxn]; bool cmp(int a,int b) { return ::a[a]< ::a[b]; //必须要在前面加上 :: } inline void Erase(int x) { nex[pre[x]]=nex[x]; pre[nex[x]]=pre[x]; } inline int read() { static int r,sign; static char c; r=0,sign=1; do {if((c=getchar())==EOF)return 0;}while(c!='-'&&(c<'0'||c>'9')); if(c=='-')sign=-1,c=getchar(); while(c>='0' && c<='9') r=r*10+(int)(c-'0'),c=getchar(); return sign*r; } int main() { int n; n=read(); for(int i=1;i<=n;i++)a[i]=read(); a[0]=a[n+1]=INF; for(int i=1;i<=n;i++)id[i]=i; sort(id+1,id+n+1,cmp); for(int i=1;i<=n;i++)nex[id[i]]=id[i+1],pre[id[i]]=id[i-1]; int ans=0; for(int i=n;i>=2;i--) { ans+=min(abs(a[nex[i]]-a[i]),abs(a[pre[i]]-a[i])); Erase(i); } printf("%d\n",ans+a[1]); return 0; }
相关文章推荐
- 【bzoj1588】[HNOI2002]营业额统计 Splay
- bzoj 1588 [HNOI2002]营业额统计 splay
- [BZOJ1588]HNOI2002营业额统计|splay
- bzoj 1588: [HNOI2002]营业额统计 splay
- bzoj1588 [HNOI2002]营业额统计 splay
- bzoj 1588 hnoi2002营业额统计 splay
- [BZOJ1588][HNOI2002][双向链表][SPLAY]营业额统计
- [Bzoj1588][HNOI2002]营业额统计 (Treap|Splay)
- [bzoj1588][HNOI2002]营业额统计——splay
- BZOJ 1588: [HNOI2002]营业额统计 双向链表 / splay / treap
- 【bzoj1588】【HNOI2002】【营业额统计】【splay】
- bzoj1588: [HNOI2002]营业额统计 SBT&&Splay
- 两道Splay小结--bzoj1112: [POI2008]砖块Klo&bzoj1588: [HNOI2002]营业额统计
- BZOJ 1588 [HNOI2002] 营业额统计 [splay做法]
- BZOJ 1588 [HNOI 2002] 营业额统计 Splay
- [BZOJ1588][HNOI2002][Treap][Splay]营业额统计[水题]
- Bzoj 1588: [HNOI2002]营业额统计(splay)
- bzoj 1588 [HNOI2002]营业额统计 splay
- bzoj1588 [HNOI2002]营业额统计 (Splay)
- Bzoj 1588: [HNOI2002]营业额统计(Splay 单点更新)