HDU 6638二维扫描线+二维最大子段和+离线

Snowy Smile HDU - 6638

题解看这位大佬,讲的很详细了。

传送门

反思

  1. 本题做的时候,已经想到二维子段和了,但不知怎么维护。
  2. 看了题解,原来要用线段树,之后暴力算答案。
  3. 先只看纵坐标,即只看y时(即一条水平的扫描线时),那么先暴力枚举所有可能的矩形(这些矩形,只知道上下界,左右边界还是未知的
  4. 对于每一次枚举y上界时(即一条水平的扫描线时),可以看一下这条水平扫描线y上是否有点,有就加入到【1,cntx】的线段树里,根据x坐标,往区间里进行修改(由于数据坐标有1e9,所以要先离线做哦( ̄▽ ̄)")
    每次遇到 上界y 上的点都维护一下【1,cntx】。
  5. 上面讲到的线段树只维护【1,cntx】。每次y的下界确定时。枚举y上界。(由于每一次变动上界y,都是一个新矩形,所以更新下答案即可)
  6. 总复杂度 n 2 l o g n n^2logn n2logn

AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define mst(x,a) memset(x,a,sizeof(x))
#define lc u<<1
#define rc u<<1|1
using namespace std;
typedef long long ll;
const int maxn=2e3+10;
struct point {
    int x,y;
    ll val;
    bool operator<(const point&p)const{
        return y<p.y||(y==p.y&&x<p.x);
    }
}p[maxn];
struct node{
    ll sum,pre,mx,suf;//除了sum,其他都是max
}tree[maxn<<2];
void clean(int u, int l ,int r){
    tree[u].sum=tree[u].mx=tree[u].pre=tree[u].suf=0;
    if(l==r)return ;
    int mid=(l+r)>>1;
    clean(lc,l,mid);
    clean(rc,mid+1,r);///mid+1
}
void pushup(int u){
    tree[u].sum=tree[lc].sum+tree[rc].sum;
    tree[u].mx=max(max(tree[lc].mx,tree[rc].mx),tree[lc].suf+tree[rc].pre);
    tree[u].pre=max(tree[lc].pre,tree[lc].sum+tree[rc].pre);
    tree[u].suf=max(tree[rc].suf,tree[rc].sum+tree[lc].suf);
}
void modify(int u, int l, int r, int x, ll val){
    if(l==r){
        tree[u].mx=tree[u].pre=tree[u].suf=(tree[u].sum+=val);
        return ;
    }
    int mid=(l+r)>>1;
    if(x<=mid)modify(lc,l,mid,x,val);
    else modify(rc,mid+1,r,x,val);///mid+1
    pushup(u);
}
int n;
int lx[maxn],ly[maxn];
int cntx,cnty;
void init(){
    cntx=cnty=0;
    scanf("%d", &n);
    for(int i=1; i<=n; i++){
        scanf("%d%d%lld",&p[i].x,&p[i].y,&p[i].val);
        lx[++cntx]=p[i].x;
        ly[++cnty]=p[i].y;
    }
    sort(p+1,p+1+n);
    sort(lx+1,lx+1+cntx);sort(ly+1,ly+1+cnty);
    cntx=unique(lx+1,lx+1+cntx)-lx-1;cnty=unique(ly+1,ly+1+cnty)-ly-1;
    for(int i=1; i<=n; i++){
        p[i].x=lower_bound(lx+1,lx+1+cntx,p[i].x)-lx;
        p[i].y=lower_bound(ly+1,ly+1+cnty,p[i].y)-ly;
    }
}
int main()
{
    int t;scanf("%d", &t);
    while(t--){
        init();
       // cout<<"ok"<<endl;
        ll ans=0;
        int pos=1;
        for(int i=1; i<=cnty; i++){
            clean(1,1,cntx);
            for(int j=i,k=pos; j<=cnty; j++){
                while(k<=n&&j==p[k].y){
                    modify(1,1,cntx,p[k].x,p[k].val);
                    k++;
                }
                if(j==i)pos=k;
                ans=max(ans,tree[1].mx);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值