2019杭电多校第六场Snowy Smile HDU-6638

本文探讨了一种解决二维平面内点集最大权值和问题的高效算法,通过避免矩阵离散化,采用线段树优化数据结构,实现n²log₂n的时间复杂度,特别适用于处理稀疏矩阵中的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接HDU - 6638
题意:二维平面内n个点,有不同的点权,问随便一个矩形(平行于x,y轴)能圈住的最大权值和为多少,可以不选。
二维的最大子段和。
谁如果把这道题中的东西离散化成一个矩阵,谁傻逼(我傻逼),离散化成这个东西的话复杂度就是 n 3 n^3 n3起步了。
具体来,离散化了x,y,然后记录每个x对应的y出现的位置及他的权值。
枚举上下边界,每次刚开始枚举的时候建一颗全部为0的线段树(离散化后的y的范围),然后下边界每下移一次,把与他同等高度的权值加到对应的点中去。
赛中一度将这个东西映射成了一个矩阵,复杂度一直压不下来。。。。。(因为本来这些点构成了一个稀疏矩阵,压缩就会变成一个稠密矩阵,里面有很多0的元素,而加0是没有意义的,所以压缩了矩阵会使复杂度多一个n)
当然这个题的时间复杂度要分析对,直观来看代码中的复杂度似乎为 n 3 ∗ l o g 2 n n^3*log_2n n3log2n,但是第二三重的循环加起来总共最多会执行n次,而一次的复杂度为log,故其实复杂度为: n 2 ∗ l o g 2 n n^2*log_2n n2log2n

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn=2009;

ll sum[maxn<<2|1];
ll dat[maxn<<2|1];
ll lmax[maxn<<2|1];
ll rmax[maxn<<2|1];

void pushup(int k){
    sum[k]=sum[k<<1]+sum[k<<1|1];
    lmax[k]=max(lmax[k<<1],sum[k<<1]+lmax[k<<1|1]);
    rmax[k]=max(rmax[k<<1|1],sum[k<<1|1]+rmax[k<<1]);
    dat[k]=max(max(dat[k<<1],dat[k<<1|1]),rmax[k<<1]+lmax[k<<1|1]);
}

void build(int l,int r,int k){
    sum[k]=dat[k]=lmax[k]=rmax[k]=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
}

void updata(int l,int r,int k,int id,ll val){
    if(l==r){
        dat[k]=rmax[k]=lmax[k]=sum[k]=sum[k]+val;
        return ;
    }
    int mid=(l+r)>>1;
    if(id<=mid) updata(l,mid,k<<1,id,val);
    else updata(mid+1,r,k<<1|1,id,val);
    pushup(k);
}

int X[maxn],Y[maxn];
int m1,m2;

ll mutil[maxn][maxn];


void quchong(int n){
    sort(X+1,X+1+n);
    sort(Y+1,Y+1+n);
    m1=unique(X+1,X+1+n)-X-1;
    m2=unique(Y+1,Y+1+n)-Y-1;
}

int getidx(int x){
    return lower_bound(X+1,X+1+m1,x)-X;
}

int getidy(int x){
    return lower_bound(Y+1,Y+1+m2,x)-Y;
}

struct Node{
    int x,y,z;
}a[maxn];

vector<pair<int,int> > v[maxn];

int main(){
    int t;
    scanf("%d",&t);
    int n;
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
            X[i]=a[i].x;
            Y[i]=a[i].y;
        }
        quchong(n);

        for(int i=1;i<=n;++i){
            int hx=getidx(a[i].x);
            int hy=getidy(a[i].y);
            v[hx].push_back({hy,a[i].z});
        }
        ll res=0;
        for(int i=1;i<=m1;++i){
            build(1,m2,1);
            for(int j=i;j<=m1;++j){
                for(int k=0;k<v[j].size();++k)
                    updata(1,m2,1,v[j][k].first,v[j][k].second);
                res=max(res,dat[1]);
            }
        }
        printf("%lld\n",res);

        for(int i=1;i<=m1;++i) v[i].clear();
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值