zoukankan      html  css  js  c++  java
  • 线段树维护区间最大子段和 枚举 HDU6638

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

    题意:在一个二维坐标系上给你n(n<=2000)个点,点带有一个价值w(有正有负),点的坐标都在(-1e9,1e9)的范围之间,可任意用一个平行于坐标轴的矩形框住一片区域,求这片区域框住的点的价值和

    分析:点的坐标范围太大,离散化应能想到。离散化后可以考虑枚举左边界,枚举左边界后按照横坐标的依次加点(以一列一列为单位),用线段树维护一列的最大子段和,每移动到新的一列,继续加点时,等价于向原先的那一列数据添加了值,每加完一列时,用一个全局变量ans来和当前列(此时已包含了好几列了,其实本质上是一个矩形)的最大子段和作比较,若ans小,则更新。

    关于线段树维护区间最大子段和:https://blog.csdn.net/wu_tongtong/article/details/73385029

    本题,我们设ls为左端点起始的最大子段和,rs为右端点起始的最大子段和,ans为区间最大子段和,sum为区间和,维和方法可见前面这个博客,也可直接看代码。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int inf=1<<30;
    const int maxn=2010;
    ll ls[maxn<<2],rs[maxn<<2],ans[maxn<<2],sum[maxn<<2];
    struct node{
        int x,y,w;
        bool operator <(const node &t) const{
            return x<t.x;
        }
    }a[maxn];
    void build(int k,int l,int r){
        ls[k]=rs[k]=ans[k]=sum[k]=0;
        if(l==r)return ;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
    }
    void pushup(int x){
        sum[x]=sum[x<<1]+sum[x<<1|1];
        ls[x]=max(ls[x<<1],sum[x<<1]+ls[x<<1|1]);
        rs[x]=max(rs[x<<1|1],sum[x<<1|1]+rs[x<<1]);
        ans[x]=max(ans[x<<1],ans[x<<1|1]);
        ans[x]=max(ans[x],rs[x<<1]+ls[x<<1|1]);
    }
    void update(int k,int l,int r,int pos,int z){
        if(l==r){
            ls[k]+=z,rs[k]+=z,sum[k]+=z,ans[k]+=z;//注意这里是加等,因为是把很多条边缩在一条边上 
            return ;
        }
        int mid=(l+r)>>1;
        if(pos<=mid) update(k<<1,l,mid,pos,z);
        else update(k<<1|1,mid+1,r,pos,z);
        pushup(k);
    }
    int tx[maxn],ty[maxn];
    int main(){
        int T;scanf("%d",&T);
        while(T--){
            int n;scanf("%d",&n);
            for(int i=1;i<=n;i++){
                scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
                tx[i]=a[i].x;ty[i]=a[i].y;
            }
            sort(tx+1,tx+n+1);
            int mx=unique(tx+1,tx+n+1)-tx-1;
            sort(ty+1,ty+n+1);
            int my=unique(ty+1,ty+n+1)-ty-1;
            for(int i=1;i<=n;i++){
                a[i].x=lower_bound(tx+1,tx+mx+1,a[i].x)-tx;
                a[i].y=lower_bound(ty+1,ty+my+1,a[i].y)-ty;
            }//以上这些步骤都是将横纵坐标离散化 
            ll ANS=0;//用来记录答案 
            sort(a+1,a+n+1);//按x排序,之后依次枚举左边界 
            for(int i=1;i<=n;i++){//变量i是用来枚举左边界的,分别从横坐标为1,到横坐标为2.....因为存在重复,横坐标为1的可能会有很多个点 
                a[0].x=i;//其实就是i,只是为了结构相同使用lower_bound函数才另外设了一个 
                int cur=lower_bound(a+1,a+n+1,a[0])-a;
                build(1,1,my);//初始化 
                for(int j=i;j<=n;j++){//从第cur个点开始,将点一个个加入 
                    while(cur<=n&&a[cur].x==j){
                        update(1,1,my,a[cur].y,a[cur].w);
                        cur++;
                    }
                    ANS=max(ANS,ans[1]);
                }
            }
            printf("%lld
    ",ANS);
        }
    } 
  • 相关阅读:
    HDU5343:MZL's Circle Zhou(SAM,记忆化搜索DP)
    动归皆背包——那些做过的背包
    CODEVS 3943 数学奇才琪露诺
    codevs 1540 银河英雄传说
    CODEVS 1004四子连棋
    洛谷1082 同余方程
    洛谷1006 传纸条
    洛谷1508 Likecloud-吃、吃、吃
    洛谷1108 低价购买
    洛谷1156 垃圾陷阱
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11326492.html
Copyright © 2011-2022 走看看