当初这题用线段树搞爆,离散化然后建树搞搞搞,辛苦AC。
其实这题用漂浮有奇效,不用离散,而且是线段,覆盖写起来简单。
想法很简单,贴在下面的海报就放在下面,然后从下往上浮,遇到其他的海报就断成一截或两截继续上浮。
还有个问题,这题的坐标表示的不是端点,而是一小段。
比如有两张海报,1 3和4 6,那么其实1到6都是被覆盖了的。
所以截断海报的时候加减一处理边界。
用DFS实现。
配合2个剪枝,在OJ跑250ms,离散线段树跑188ms。但线段树空间10000K,用漂浮不用建树的空间。
具体看代码。
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int le[10005],re[10005]; //左右端点
int n;
bool pf(int l,int r,int c){
while(c<n&&(l>re[c]||r<le[c])) c+=1; //剪枝1 现在的区域和当前判断的海报没交点 直接判下一个海报
if(c>=n) {
if(r-l+1) return 1; //当前的海报范围合法
else return 0;
}
if(le[c]<=l&&re[c]>=r) return 0; //剪枝2 已被完全覆盖
int flag=0;
if(l<le[c]) flag=pf(l,min(le[c],r)-1,c+1); //这里由于是统计可见数量 左边可以看见就不用管右边了
if(!flag&&r>re[c]) flag=pf(max(re[c],l)+1,r,c+1);
return flag;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int ans=0;
for(int i=0;i<n;++i) scanf("%d%d",&le[i],&re[i]);
for(int i=0;i<n;++i)
if(pf(le[i],re[i],i+1)) ans+=1;
printf("%d\n",ans);
}
}