您的位置:首页 > 其它

【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;
}




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: