HFUT 1287 法默尔的农场 [安徽省第三届省赛]

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

题目:http://acm.hfut.edu.cn/OnlineJudge/

当时比赛最悲剧的一题,大约花了两个小时,最终也没能AC。

唯一值得安慰的是,我成功的想到了用线段树来解,但是悲剧也在这,虽然如此但是没有过,好可惜。

题目没有更新,只有查询,这让我忽视了边查询边更新,只在查询上优化,最终导致悲剧。

吸取教训啊,线段树就一定要发挥他的优势才行。

题目中文的,就不解释了。

保存区间的最大值和最小值,那么如果水位低于最小值则说明区间内都没有被淹,如果大于最大值则说明区间内全被淹,否则查询子区间。

由于递归到子区间的时候,两个区间相邻的部分可能形成一个岛,所以还得记录区间的两端是否被淹没。(这些我当时都考虑到了,用位运算+标记成功完成)

离线查询,按高度递增查询,便可以更新区间最小值,剔除部分区间。

比赛的时候只考虑到 1 1W 1 1W 1 1W这样的坑爹数据,便想到用离散化来优化,结果还是悲剧了,哎。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 1<<30
using namespace std;
struct Line{
	int left,right,mid;
	int mmax,mmin;
	int lx,mx,rx;
}L[100005];
struct Node{
	int h,id;
}Q[20005];
int a[20005];
void bulid(int step,int l,int r){
	L[step].left=l;
	L[step].right=r;
	L[step].mid=(l+r)/2;
	L[step].lx=L[step].mx=L[step].rx=1;
	if(l==r){
		L[step].mmax=L[step].mmin=a[l];	
		return;
	}
	bulid(2*step,l,(l+r)/2);
	bulid(2*step+1,(l+r)/2+1,r);
	L[step].mmax=max(L[step*2].mmax,L[2*step+1].mmax);
	L[step].mmin=min(L[step*2].mmin,L[2*step+1].mmin);
}
void update(int step){
	L[step].mx=L[2*step].mx+L[2*step+1].mx-(L[2*step].rx&L[2*step+1].lx);
	L[step].lx=L[2*step].lx;
	L[step].rx=L[2*step+1].rx;
}
void query(int step,int h){
	if(h<L[step].mmin)
		return ;
	if(h>=L[step].mmax){
		L[step].mmin=inf;
		L[step].rx=L[step].lx=L[step].mx=0;
		return ;
	}
	query(2*step,h);
	query(2*step+1,h);
	update(step);
	if(L[2*step].mmin==inf)
		L[step].mmin=L[2*step+1].mmin;
	else if(L[2*step+1].mmin==inf)
		L[step].mmin=L[2*step].mmin;
	else
		L[step].mmin=min(L[2*step].mmin,L[2*step+1].mmin);
}
bool cmp(Node n1,Node n2){
	return n1.h<n2.h;
}
int ans[20005];
int main(){
	int n,q;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	bulid(1,1,n);
	scanf("%d",&q);
	for(int i=0;i<q;i++){
		scanf("%d",&Q[i].h);
		Q[i].id=i;
	}
	sort(Q,Q+q,cmp);
	for(int i=0;i<q;i++){
		query(1,Q[i].h);
		ans[Q[i].id]=L[1].mx;
	}
	for(int i=0;i<q;i++)
		printf("%d\n",ans[i]);
	return 0;
}
/*
10
6 2 9 8 10 1 5 3 9 7
2
5
4
*/




  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值