HDU-5714-拍照(区间线段覆盖)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5714


拍照
Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)



Problem Description
小明在旅游的路上看到了一条美丽的河,河上有许多船只,有的船只向左航行,有的船只向右航行。小明希望拍下这一美丽的风景,并且把尽可能多的船只都完整地拍到一张照片中。


小明位于河的边上,并且可以在河边的任意位置进行拍照,照相机的视野恰好为90度角,只能以垂直于河边的方向进行拍照。河上的船只全都可看作是平行于河边的一条线段,跟河边的距离各不相同,有的正在向左移动,有的正在向右移动,但移动速度恰好都是一样的。小明可以等待恰当的时间让尽量多的船只都走进照相机的视野里,你不需要考虑船只之间会互相遮挡视野的情况。

Input
第一行为T,表示输入数据组数。
下面T组数据,对于每组数据:
第一行是一个数n(1≤n≤104),表示船只的数量。
接下来n行,每行四个整数
x,y,z,d(−106≤x<y≤106,1≤z≤104),表示船只的左端点位置、右端点位置、距离河边的距离,以及航行的方向。d为−1表示向左航行,1表示向右航行。

Output
对第i组数据,输出
Case #i:
然后输出一行,仅包含一个整数,表示最多可以拍到多少完整的船只。

Sample Input
3
2
1 3 1 1
2 4 1 -1
2
1 3 1 -1
2 4 1 1
1
1 4 1 1


Sample Output

Case #1:
2
Case #2:
1
Case #3:
0


题解:对于船[x,y,z],可以在[y-z,x+z]这些位置观测到它,那么就得到了n条线段,由于船速相同,根据运动方向,问题转换为两部分固定线段,一部分左移,一部分右移,求两线段覆盖点的最大值,我们只需要维护下右移线段的左区间最大值,以及左移线段的右区间最大值,那么对于某点i,能观测到的最大值就是左右维护最大值的和。遍历O(n),点排序O(nlog(n));


#include <bits/stdc++.h>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define bug cout<<"bug"<<endl
const int MAXN = 2e5+7;
int N,M,K;
int len1[MAXN],len2[MAXN];
int ans[MAXN];
struct node
{
    int a,lef,dir;
}point[MAXN];
int index;
void add_point(int a, int p, int f)
{
    point[++index].a=a;
    point[index].lef=p;
    point[index].dir=f;
}
bool cmp(node x, node y)
{
    if(x.a!=y.a)return x.a<y.a;
    if(x.lef!=y.lef)return x.lef>y.lef;
    return x.dir>y.dir;
}
int main()
{
    int T;
    scanf("%d",&T);
    int cas=0;
    while(T--)
    {
        index=0;
        int a,b,x,y,z,p;
        scanf("%d",&N);
        for(int i=0; i<N; ++i)
        {
            scanf("%d%d%d%d",&x,&y,&z,&p);
            a=y-z,b=x+z;
            if(a<=b)
            {
                add_point(a,1,p);
                add_point(b,0,p);
            }
        }
        sort(point+1,point+index+1,cmp);
        ans[0]=0;
        int temp=0;
        for(int i=1; i<=index; ++i)
        {
            if(point[i].dir==1 && point[i].lef)++temp;
            ans[i]=max(ans[i-1],temp);
            if(point[i].dir==1 && !point[i].lef)--temp;
        }
        int f=0,t=0;temp=0;
        for(int i=index; i>0; --i)
            if(point[i].dir==-1)
            {
                if(!point[i].lef)++temp;
                t=max(t,temp);
                f=max(f,ans[i]+t);
                if(point[i].lef)--temp;
            }
        printf("Case #%d:\n%d\n",++cas,f);
    }
    return 0;
}
/*
3
2
2 3 1 1
0 1 1 -1
2
1 3 1 -1
2 4 1 1
1
1 4 1 1
*/







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值