2019hdu暑假多校训练赛第六场1005 Snowy Smile hdu6638(线段树区间连续子段和最大,区间合并)

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

 

题意:在一个二维平面内给出n个点每个点有权值,要求画一个矩形使得这个矩形内的点的权值和最大。

数据范围:1≤T≤100,1≤n≤2000,−1e9≤xi,yi,wi≤1e9,∑n≤10000

 

思路:首先离散化,对于每次点数最多是2000个所以离散化后最大是一个2000*2000的地图这时候只需要找一个矩形内的权值和最大就行,所以我们可以用n*n去枚举上下界,对于每一个上下界建一棵线段树维护一下区间连续字段和最大即可。剩下就是模板的区间合并了,具体都写在update函数里了。

#include <bits/stdc++.h>
#define ls (x<<1)
#define rs (x<<1|1)
using namespace std;
typedef long long ll;
const int N=2e3+10;
int n,m,t,xx[N],yy[N],val[N],idx[N],idy[N];
vector<int>G[N];
struct Tree{
    ll sum,maxx,maxl,maxr;
}tree[N<<2];
void build(int x,int l,int r){
    tree[x].maxx=tree[x].sum=tree[x].maxl=tree[x].maxr=0;
    if(l==r)return ;
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void update(int x,int l,int r,int pos,int val){
    if(l==r){
        tree[x].sum+=val;
        tree[x].maxx=tree[x].maxl=tree[x].maxr=tree[x].sum;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)update(ls,l,mid,pos,val);
    if(pos>mid)update(rs,mid+1,r,pos,val);
    tree[x].sum=tree[ls].sum+tree[rs].sum;
    tree[x].maxl=max(tree[ls].maxl,tree[ls].sum+tree[rs].maxl);
    tree[x].maxr=max(tree[rs].maxr,tree[rs].sum+tree[ls].maxr);
    tree[x].maxx=max(max(tree[ls].maxx,tree[rs].maxx),tree[ls].maxr+tree[rs].maxl);
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)G[i].clear();
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&xx[i],&yy[i],&val[i]);
            idx[i]=xx[i],idy[i]=yy[i];
        }
        sort(xx+1,xx+n+1),sort(yy+1,yy+n+1);
        for(int i=1;i<=n;i++){
            idx[i]=lower_bound(xx+1,xx+n+1,idx[i])-xx;
            idy[i]=lower_bound(yy+1,yy+n+1,idy[i])-yy;
            G[idy[i]].push_back(i);
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
            build(1,1,n);
            for(int j=i;j<=n;j++){
                int len=G[j].size();
                for(int k=0;k<len;k++)
                    update(1,1,n,idx[G[j][k]],val[G[j][k]]);
                ans=max(ans,tree[1].maxx);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值