您的位置:首页 > 其它

两道Splay小结--bzoj1112: [POI2008]砖块Klo&bzoj1588: [HNOI2002]营业额统计

2014-10-13 22:32 579 查看
两道都不是难题,是比较浅显的Splay实现,但是调试了很久,真的是调试的姿势不对吗?

Noip将近,虽然不知道初赛如何,先写着再说吧。

bzoj1112:对于每一段我们假设是我们要求的连续区间,那么怎么做可以使得代价最小呢?经典的取中位数。

                 由于要快速的删除并插入节点,还要查询第k大值,不用平衡树用什么?上Splay。

bzoj1588:一道以前做过的题目,好像bzoj上的数据有点问题,导致我修改完WA再修改再WA。坚持不懈一整版,AC率都掉下百分之三了。

                 最后烦起来了,向管理要数据,然后得到的回复是:数据有问题。 T_T

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Code

1112

#include<iostream>
#include<cstdio>
#include<cmath>
#include<climits>
#include<algorithm>
#define L(x) T[T[x].s[0]]
#define R(x) T[T[x].s[1]]
#define F(x) T[T[x].f]
using namespace std;
typedef long long ll;
const ll N=101000,INF=100000000000;
struct BST{
int s[3],f,ws,v;
ll sumv,sumx;
}T
;int root,cnt=0;
int n,k,a
;
ll ans=INF;

void New(int &p,int ws,int f,ll v){
p=++cnt;
T[p].ws=ws; T[p].v=v; T[p].f=f;
T[p].s[0]=T[p].s[1]=0;
T[p].sumv=v; T[p].sumx=1;
}

void Upd(int p){
T[0].v=T[0].sumx=T[0].sumv=0;
T[p].sumx=L(p).sumx+R(p).sumx+1;
T[p].sumv=L(p).sumv+R(p).sumv+T[p].v;
}

void Sets(int f,int p,int ws){
T[T[p].f=f].s[T[p].ws=ws]=p;
Upd(f);
}

void Rot(int p){
int ws=T[p].ws,f=T[p].f,pf=F(p).f;
if(pf) Sets(pf,p,F(p).ws);else{T[p].f=0;root=p;}
if(T[p].s[ws^1]) Sets(f,T[p].s[ws^1],ws);else{
T[f].s[ws]=0;
Upd(f);
}Sets(p,f,ws^1);
}

void Splay(int p,int d){
for(;T[p].f!=d;Rot(p)) if(F(p).f){
if(T[p].ws==F(p).ws) Rot(T[p].f);
else Rot(p);
}
}
void Ins(int p,ll v){
if(!p){New(root,0,0,v); return;}
while(T[p].s[v>T[p].v]) p=T[p].s[v>T[p].v];
New(T[p].s[v>T[p].v],v>T[p].v,p,v);
Splay(T[p].s[v>T[p].v],0);
}

void Del(int p){
Splay(p,0);
ll t=T[p].s[0];
R(p).f=L(p).f=0;
if(!T[p].s[1]){root=T[p].s[0];return;}
if(!t){root=T[p].s[1];return;}
while(T[t].s[1]) t=T[t].s[1];
Splay(t,0);
Sets(t,T[p].s[1],1);
}

int Kth(int p,int k){
if (L(p).sumx+1==k) return p;
if (L(p).sumx+1<k) return Kth(T[p].s[1],k-L(p).sumx-1);
else return Kth(T[p].s[0],k);
}

void Work(){
Splay(Kth(root,(k+1)>>1),0);
ll mid=T[root].v,val,p=root;
val=(mid*L(p).sumx-L(p).sumv)+(R(p).sumv-mid*R(p).sumx);
ans=min(ans,val);
}

int main(){
freopen("1112.in","r",stdin);
freopen("1112.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=k;i++) Ins(root,a[i]);
Work();
for(int i=k+1;i<=n;i++){
Del(i-k);
Ins(root,a[i]);
Work();
}printf("%lld\n",ans);
return 0;
}我的问题是出在Del函数的部分,实际上首先我应该特判特殊情况:根节点左右儿子之一是不存在的。
但是我忘了考虑右儿子,于是就出现了原来的左子树和一个根本不存在的点合并了!

我是在删除点的时候发现根节点统计出来的节点总数没变才关注到Del函数的。不然我死也想不到是Del写错了。

1588

#include<iostream>
#include<cstdio>
#include<cmath>
#include<climits>
#include<algorithm>
#define L(x) T[T[x].s[0]]
#define R(x) T[T[x].s[1]]
#define F(x) T[T[x].f]
using namespace std;
const int N=101000,INF=INT_MAX;
struct BST{
int s[3],f;
int ws,v;
}T
;int root,cnt=0;
int n;

void New(int &p,int ws,int f,int v){
p=++cnt;
T[p].ws=ws; T[p].v=v; T[p].f=f;
T[p].s[0]=T[p].s[1]=0;
}
void Sets(int f,int p,int ws){T[T[p].f=f].s[T[p].ws=ws]=p;}
void Rot(int p){
int ws=T[p].ws,f=T[p].f,pf=F(p).f;
if(pf) Sets(pf,p,F(p).ws);else{T[p].f=0;root=p;}
if(T[p].s[ws^1]) Sets(f,T[p].s[ws^1],ws);else T[f].s[ws]=0;
Sets(p,f,ws^1);
}
void Splay(int p){
for(;T[p].f;Rot(p)) if(F(p).f){
if(T[p].ws==F(p).ws) Rot(T[p].f);
else Rot(p);
}
}
void Ins(int p,int v){
while(T[p].s[v>T[p].v]) p=T[p].s[v>T[p].v];
New(T[p].s[v>T[p].v],v>T[p].v,p,v);
Splay(T[p].s[v>T[p].v]);
}
int PRED(int p){
int t=T[p].s[0];
if (t==0) return INF;
while(T[t].s[1]) t=T[t].s[1];
return abs(T[t].v-T[p].v);
}
int SUCC(int p){
int t=T[p].s[1];
if (t==0) return INF;
while(T[t].s[0]) t=T[t].s[0];
return abs(T[t].v-T[p].v);
}
int main(){
freopen("1588.in","r",stdin);
freopen("1588.out","w",stdout);
int vv,ans=0;
scanf("%d",&n);
scanf("%d",&vv);
New(root,0,0,vv);
ans+=vv;
for(int i=1;i<n;i++){
scanf("%d",&vv);
Ins(root,vv);
ans+=min(SUCC(root),PRED(root));
}printf("%d\n",ans);
return 0;
}这道题实现比较轻松,主要是被Bzoj的数据卖了。。

By the way,被初赛结束oi生涯是有多惨!?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: