HDU多校第六场——HDU6638 Snowy Smile(线段树区间合并)

题意:有n个点(n<=2000),每个点都有价值,求一个矩形内所有点价值和的最大值是多少

一维的静态最大子段和用dp在O(n)时间内解决,带修改查询区间最大子段和可以用线段树区间合并O(nlogn)写

二维的最大子矩阵和可以通过压行再dpO(n^3)写。

这题对坐标离散化一下就转化为求最大子矩阵和的问题了,然后n^3肯定是不行的,然后利用离散后是2000*2000的图上有2000个点,矩阵很稀疏这个性质,可以通过枚举起始行s,终点行e,用然后用线段树维护s~e行,每列的信息,转化为一维最大子段和来算。每次枚举起始行时都要重新建树,然后枚举终点行时,都把这行的信息更新到线段树里去,复杂度是n(nlogn(建树)+nlogn(更新)),这题关键是有效点很少只有n个,如果是n^2个就没了。

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
typedef pair<int,int>pii;
const ll inf=9e18;
const int maxn=2000+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
vector<pii>row[maxn];
struct node{
    int x,y,w;
}p[maxn];
int lshx[maxn],lshy[maxn],cnt1,cnt2;
ll maxx[maxn<<2],lmaxx[maxn<<2],rmaxx[maxn<<2],sum[maxn<<2];
void pushup(int rt)
{
    sum[rt]=sum[ls]+sum[rs];
    lmaxx[rt]=max(lmaxx[ls],sum[ls]+lmaxx[rs]);
    rmaxx[rt]=max(rmaxx[rs],sum[rs]+rmaxx[ls]);
    maxx[rt]=max(maxx[ls],maxx[rs]);
    maxx[rt]=max(maxx[rt],rmaxx[ls]+lmaxx[rs]);
}
void update(int rt,int L,int R,int pos,int val){
    if(L==R)
    {
        sum[rt]+=val;
        maxx[rt]=lmaxx[rt]=rmaxx[rt]=max(0LL,sum[rt]);
        return ;
    }
    int mid=(L+R)>>1;
    if(pos<=mid)
        update(ls,L,mid,pos,val);
    else
        update(rs,mid+1,R,pos,val);
    pushup(rt);
}
int main(){
    int t,n;
    ll ans;
    scanf("%d",&t);
    while(t--)
    {
        ans=-inf;
        cnt1=cnt2=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) row[i].clear();
        for(int i=1;i<=n;i++) scanf("%d%d%d",&(p[i].x),&(p[i].y),&(p[i].w)),lshx[++cnt1]=p[i].x,lshy[++cnt2]=p[i].y;
        sort(lshx+1,lshx+cnt1+1);
        sort(lshy+1,lshy+cnt2+1);
        cnt1=unique(lshx+1,lshx+cnt1+1)-lshx-1;
        cnt2=unique(lshy+1,lshy+cnt2+1)-lshy-1;
        for(int i=1;i<=n;i++)
        {
            int tmpx,tmpy;
            tmpx=lower_bound(lshx+1,lshx+cnt1+1,p[i].x)-lshx;
            tmpy=lower_bound(lshy+1,lshy+cnt2+1,p[i].y)-lshy;
            row[tmpx].push_back(make_pair(tmpy,p[i].w));
        }
        for(int i=1;i<=cnt1;i++)
        {
            for(int j=1;j<=cnt2*4;j++)
                maxx[j]=lmaxx[j]=rmaxx[j]=sum[j]=0;
            for(int j=i;j<=cnt1;j++)
            {
                for(int k=0;k<row[j].size();k++)
                    update(1,1,cnt2,row[j][k].first,row[j][k].second);
                ans=max(ans,maxx[1]);
            }
        }
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/eason9906/p/11754718.html