转载请注明出处,谢谢 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
*/