[CODEVS3032]摆放球 解题报告

这个题本来我是想练堆用的,结果堆没练出来,倒是练了练线段树。

此题属于那种看起来特别简单,一做起来做出翔的那种;交了六遍,对拍了N年才A。

主要需要注意的是这么几点:

1、节点保存什么信息?

题目中让求的是距离最大,但这玩意儿在线段树中不太好办;

我一开始想当然地写成了r-l式的距离,结果合并信息的时候呵呵了。

更好的做法是保存区间中连续一段空橱子的个数:①设置变量意义时一定要从易于理解和调试的角度出发。

显然,最长连续区间的左右端点也是需要保存的,因为我们需要用它来求出球该放在什么地方。但是!若一个区间的长度为0,它的左右端点应该是哪里?

2、②若[l,r]的长度为0,则令l=r+1,r=l-1.

为什么?看看在合并的时候我们做了什么?

设struct TS{int lmax,lR,rmax,rL,max,L,R}

if(tree[node<<1].lR=((l+r)>>1)+1){

tree[node].lmax+=tree[node<<1|1].lmax;

tree[node].lR=tree[node<<1|1].lR;

}

这时,若tree[node<<1|1].lmax=0会发生什么呢?

若设此时tree[node<<1|1].lR=(l+r)>>1的话,则

tree[node<<1].lR=(l+r)>>1.

是正确的。

所以。。就这样吧。

3、③三个变量中选择最大的哪个该怎么做?

很容易混乱。。

条理清晰?

把条件都完整的列出来!

if(a>=b&&a>=c){}

if(b>=a&&b>=c){}

if(c>=a&&c>=b){}

4、球该放在哪?

显然球应该放在最长的连续无球橱子区间中,但是。。具体在哪里呢?

设区间[L,R]为一个最长连续无球橱子区间,且L>1,R<N.

则显然④球应该放在L-1与R+1的中位数的位置,才能使球与L-1和R+1的距离的最小值最大。

即x=(L-1+R+1)>>1=(L+R)>>1.

5、⑤特殊区间

从1往右延伸的区间与从N往左延伸的区间,球在这里的距离长度就是区间长度!

6、记录的max?

这时我们发现一个很大很大的问题!就是节点中记录max,它不是那个最短距离,最短距离应该是max+1>>1!

也就是说,若果我们按max的大小比较,永远在max最大的前提下选择左边的那个,很可能会导致只比当前选出的max小1而其+1>>1与当前选出的max相同且在其右边的max被漏掉导致全盘皆输!

但是,如果我们不按max来选,是否可能导致当前选出的max比较小,使得之后合成的max比实际选出的max要小呢?也就是说一个max差了1不算,但两个差了2就不一样了啊!

但是我们突然发现了一个问题!max不会被合成,唯一与max有关的运算只是Cmp;合成是交给lmax和rmax的,而lmax和rmax又不需要Cmp!

于是。。在无数遍的WA与摸爬滚打之中,我们终于找到了正解的道路。。

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
struct TS{
	int lmax,rmax,max,L,R,lR,rL;
}tree[800000];
int point[1000001];
#define root 1,1,N
#define lson node<<1,l,(l+r)>>1
#define rson node<<1|1,((l+r)>>1)+1,r
inline void update(int node,int l,int r,int x,int A){
	if(l==r)
		if(A)tree[node]=(TS){1,1,1,x-1,x+1,x+1,x-1};
		else tree[node]=(TS){0,0,0,r,l,l,r};
	else{
		int m=(l+r)>>1;
		if(x>m)update(rson,x,A);
		else update(lson,x,A);
		
		tree[node].lmax=tree[node<<1].lmax;
		if(tree[node<<1].lR==m+1){
			tree[node].lmax+=tree[node<<1|1].lmax;
			tree[node].lR=tree[node<<1|1].lR;
		}
		else tree[node].lR=tree[node<<1].lR;
		
		tree[node].rmax=tree[node<<1|1].rmax;
		if(tree[node<<1|1].rL==m){
			tree[node].rmax+=tree[node<<1].rmax;
			tree[node].rL=tree[node<<1].rL;
		}
		else tree[node].rL=tree[node<<1|1].rL;
		
		int tmp=tree[node<<1].rmax+tree[node<<1|1].lmax;
		if(tree[node<<1].max+1>>1>=tree[node<<1|1].max+1>>1&&tree[node<<1].max+1>>1>=tmp+1>>1){
			tree[node].max=tree[node<<1].max;
			tree[node].L=tree[node<<1].L;
			tree[node].R=tree[node<<1].R;
		}
		else
			if(tmp+1>>1>=tree[node<<1].max+1>>1&&tmp+1>>1>=tree[node<<1|1].max+1>>1){
				tree[node].max=tmp;
				tree[node].L=tree[node<<1].rL;
				tree[node].R=tree[node<<1|1].lR;
			}
			else{
				tree[node].max=tree[node<<1|1].max;
				tree[node].L=tree[node<<1|1].L;
				tree[node].R=tree[node<<1|1].R;
			}
	}
	//cout<<l<<","<<r<<":"<<tree[node].max<<"("<<tree[node].L<<"->"<<tree[node].R<<")"<<" "<<tree[node].lmax<<"("<<l<<"->"<<tree[node].lR<<")"<<" "<<tree[node].rmax<<"("<<tree[node].rL<<"<-"<<r<<")\n";
}
inline void build(int node,int l,int r){
	tree[node]=(TS){r-l+1,r-l+1,r-l+1,l-1,r+1,r+1,l-1};
	if(l!=r)build(lson),build(rson);
}
inline void out(int node,int l,int r){
	if(l!=r)out(lson),out(rson);
	else cout<<!tree[node].max;
}
int main(){
	freopen("CODEVS3032.in","r",stdin);
	//freopen("CODEVS3032.out","w",stdout);
	memset(tree,0,sizeof(tree));
	int N,M,flag,A,x,tot=0,l,m,r;
	scanf("%d%d",&N,&M);
	build(root);
	while(M--){
		scanf("%d%d",&flag,&A);
		if(flag-1)update(root,point[A],1);
		else{
			//cout<<tree[1].lmax<<" "<<(tree[1].max+1>>1)<<" "<<tree[1].rmax<<endl;
			if(tree[1].lmax>=tree[1].rmax&&tree[1].lmax>=tree[1].max+1>>1)x=1;
			else
				if(tree[1].max+1>>1>=tree[1].rmax&&tree[1].max+1>>1>=tree[1].lmax)x=(tree[1].L+tree[1].R)>>1;
				else x=N;
			printf("%d\n",x);
			update(root,x,0);
			point[A]=x;
		}/*
		cout<<flag<<" "<<A<<":";
		out(root);
		cout<<endl;*/
	}
}

⑦重要总结:不论是多么简单的题,一定要写对拍!这个题中一半的问题全是拍出来的!有很多题都是看似简单实则不易。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值