2019 hdu 多校6 Snowy Smile(线段树维护最大子段和)

链接

题意:

给出2000个点,点的x和y的坐标范围为(-1e9,1e9),可以用一个矩形去包括一些点,求被包括的点的权值和最大是多少。矩形的长宽平行于坐标轴。



思路:

一开始看到这个题瞬间就想到了先把点的坐标离散化,然后就是 n 3 n^3 n3的最大子矩阵和的套路,可惜时间复杂不对。一个可行的做法:同样先对点进行离散化,然后利用线段树维护动态子段和,不知道这个的话可以百度学习一下。最后不能像 n 3 n^3 n3的做法那样去枚举上下边,这样复杂度就会更高了,有些点是多出来的无效状态。只需要先对点按照x降序,y降序或者其他的规则去排序,

x=1,y=2
x=2,y=1 | x=2,y=2 | x=2,y=4
x=3,y=4 | x=3,y=8

因为都是有序的,很容易就可以判断点在哪一行了,然后只要枚举点即可,复杂度: n 2 l o g ( n ) n^2log(n) n2log(n)

下面的代码方向是从左向右的。


参考代码:

#include 
using namespace std;
typedef long long ll;
const int INF=1e9+7;
struct _point{
    int x,y;
    ll w;
    bool operator <(const _point &a)const {
        if(y==a.y)return x<a.x;
        return y<a.y;
    }
}po[2005];
int lsx[2005];
int lsy[2005];
int szx,szy;

template <typename _Tp> inline _Tp read(_Tp&x){
    char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

struct node{
        ll sum,ll,lr,lm;
}tree[4005*4];

#define lson rt<<1
#define rson rt<<1|1

void pushup(int rt){
    tree[rt].sum=tree[lson].sum+tree[rson].sum;
    tree[rt].ll=max(tree[lson].ll,tree[lson].sum+tree[rson].ll);
    tree[rt].lr=max(tree[rson].lr,tree[rson].sum+tree[lson].lr);
    tree[rt].lm=max(tree[lson].lr+tree[rson].ll,max(tree[lson].lm,tree[rson].lm));
}

void build(int rt,int l,int r){
    tree[rt].ll=tree[rt].sum=tree[rt].lr=tree[rt].lm=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
}

void update(int rt,int l,int r,int x,ll k){
    if(l==r){
        tree[rt].sum+=k;
        tree[rt].ll=max(0ll,tree[rt].sum);
        tree[rt].lm=max(0ll,tree[rt].sum);
        tree[rt].lr=max(0ll,tree[rt].sum);
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid)update(lson,l,mid,x,k);
    else update(rson,mid+1,r,x,k);
    pushup(rt);
}

ll query(int rt,int l,int r,int x,int y){
    if(x<=l&&r<=y){
        return max(tree[rt].lm,max(tree[rt].ll,tree[rt].lr));
    }
    int mid=(l+r)>>1;
    if(y<=mid)return query(lson,l,mid,x,y);
    else if(x>mid)return query(rson,mid+1,r,x,y);
    else return max(query(lson,l,mid,x,mid),query(rson,mid+1,r,mid+1,y));
}

int main(){
    int t;
    read(t);
    po[0].y=-INF;
    for(int ca=1;ca<=t;ca++){
        int n;
        read(n);
        for(int i=1;i<=n;i++){
            read(po[i].x),read(po[i].y),read(po[i].w);
            lsx[i]=po[i].x;
            lsy[i]=po[i].y;
        }
        sort(lsx+1,lsx+1+n);
        sort(lsy+1,lsy+1+n);
        szx=unique(lsx+1,lsx+1+n)-lsx-1;
        szy=unique(lsy+1,lsy+1+n)-lsy-1;
        sort(po+1,po+1+n);
        for(int i=1;i<=n;i++){
            po[i].x=lower_bound(lsx+1,lsx+1+szx,po[i].x)-lsx;
            po[i].y=lower_bound(lsy+1,lsy+1+szy,po[i].y)-lsy;
        }
        ll ans=0ll;
        int l=1;
        while(l<=n){
            while(po[l].y==po[l-1].y) l++;
            build(1,1,szx);
            int r=l;
            while(r<=n){
                update(1,1,szx,po[r].x,po[r].w);
                while(r<n&&po[r+1].y==po[r].y){
                    r++;update(1,1,szx,po[r].x,po[r].w);
                }
                ans=max(ans,query(1,1,szx,1,szx));
                r++;
            }
            l++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(2019 hdu 多校6 Snowy Smile(线段树维护最大子段和))