Gym 101666M (线段树)

传送门

题面:PDF

题意:

    给你一个起点s和终点e,有n个地点,问你在不增加从s到e的曼哈顿距离的前提下的能够到达的最多的地点的个数。

题目分析:

    跟2018CCPC网络赛的一题(HDU 6447)一摸一样,只不过这个题中还需要讨论一下起点和终点的相对位置。

    我们只需要先将y坐标离散化,并根据每个点的x坐标从小到大遍历,并且用线段树对这个点维护它的1到id[y]的最大值即可。

代码:

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
struct ST{
    int maxx;
}tr[maxn<<2];
struct Street{
    int x,y,id;
}q[maxn];
bool cmp1(Street a,Street b){
    if(a.x==b.x) return a.y<b.y;
    return a.x>b.x;
}
bool cmp2(Street a,Street b){
    if(a.x==b.x) return a.y>b.y;
    return a.x>b.x;
}
bool cmpy(Street a,Street b){
    return a.y<b.y;
}
void push_up(int rt){//线段树维护区间最大值
    tr[rt].maxx=max(tr[rt<<1].maxx,tr[rt<<1|1].maxx);
}
void update(int l,int r,int rt,int C,int val){
    if(l==r){
        tr[rt].maxx=val;
        return ;
    }
    int mid=(l+r)>>1;
    if(C<=mid) update(l,mid,rt<<1,C,val);
    else update(mid+1,r,rt<<1|1,C,val);
    push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r) return tr[rt].maxx;
    int mid=(l+r)>>1;
    int maxx=0;
    if(L<=mid) maxx=max(maxx,query(L,R,l,mid,rt<<1));
    if(R>mid) maxx=max(maxx,query(L,R,mid+1,r,rt<<1|1));
    return maxx;
}
int main()
{
    int n;
    scanf("%d",&n);
    Street s,e;
    scanf("%d%d%d%d",&s.x,&s.y,&e.x,&e.y);
    if(n==0){
        puts("0");return 0;
    }
    for(int i=1;i<=n;i++) scanf("%d%d",&q[i].x,&q[i].y);
    //坐标离散化
    sort(q+1,q+1+n,cmpy);
    int cnt=2,yy=q[1].y;
    q[1].id=cnt;
    for(int i=2;i<=n;i++){
        if(yy==q[i].y) q[i].id=cnt;
        else yy=q[i].y,q[i].id=++cnt;
    }
    if(s.x>e.x) swap(s,e);
    if(s.y>e.y){//起始点在终点的左下
        sort(q+1,q+1+n,cmp1);
        for(int i=1;i<=n;i++){
            if(q[i].x<s.x||q[i].x>e.x) continue;
            if(q[i].y<e.y||q[i].y>s.y) continue;
            //查询1到idy[i]的最大值
            int tmp=query(1,q[i].id,1,cnt,1);
            //加上一个的点对答案的影响
            update(1,cnt,1,q[i].id,tmp+1);
        }
    }
    else{//起始点在终点的右上
        sort(q+1,q+1+n,cmp2);//同理上面
        for(int i=1;i<=n;i++){
            if(q[i].x<s.x||q[i].x>e.x) continue;
            if(q[i].y<s.y||q[i].y>e.y) continue;
            int tmp=query(q[i].id,cnt,1,cnt,1);
            update(1,cnt,1,q[i].id,tmp+1);
        }
    }
    cout<<query(1,cnt,1,cnt,1)<<endl;
}
原文地址:https://www.cnblogs.com/Chen-Jr/p/11007200.html