[漂浮法]POJ2528 Mayor's posters

当初这题用线段树搞爆,离散化然后建树搞搞搞,辛苦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);
    }
}


你可能感兴趣的:(ACM,poj)