最大权值和矩阵、线段树维护最大子段和

Snowy Smile

求最大子矩阵,枚举一个上界,从上往下将同一行的数值丢到线段树里面去维护好最大子段和。一行结束后当前的最大子段和意味着在上界(枚举的)和下界(枚举)确定的情况下,所有子矩阵(左边界为最大子段初始,右边界为结束)中,和最大的那个。那么所有最大子段和最大的那个就是答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn=4e3+22;
#define sfi(a) scanf("%d",&a)
#define sfl(a) scanf("%lld",&a)
#define sff(a) scanf("%lf",&a)
int n,m;
struct Point
{
	int x,y;LL val;
	bool operator<(const Point b)const
	{
		if(y==b.y)return x<b.x;
		return y>b.y;
	}
}node[maxn];
int hashx[maxn],hashy[maxn];
struct Segmentree
{
	LL dat,ldat,rdat,sum;int l,r;
	#define l(p) tre[p].l
	#define r(p) tre[p].r
	#define dat(p) tre[p].dat
	#define sum(p) tre[p].sum
	#define ldat(p) tre[p].ldat
	#define rdat(p) tre[p].rdat
}tre[maxn<<2];
void pushup(int p)
{
	sum(p)=sum(p<<1)+sum(p<<1|1);
	ldat(p)=max(ldat(p<<1),sum(p<<1)+ldat(p<<1|1));
	rdat(p)=max(rdat(p<<1|1),sum(p<<1|1)+rdat(p<<1));
	dat(p)=max(rdat(p<<1)+ldat(p<<1|1),max(dat(p<<1|1),dat(p<<1)));
	dat(p)=max(dat(p),max(sum(p),max(ldat(p),rdat(p))));
}
void build(int p,int l,int r)
{
	l(p)=l;r(p)=r;dat(p)=ldat(p)=rdat(p)=sum(p)=0;
	if(l==r){return;}
	int mid=(l(p)+r(p))/2;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
	pushup(p);
}
void addtre(int p,int x,LL val)
{
	if(l(p)==r(p)&&l(p)==x)
	{
		sum(p)=sum(p)+val;
		dat(p)=ldat(p)=rdat(p)=sum(p);
		return;
	}
	int mid=(l(p)+r(p))/2;
	if(x<=mid)addtre(p<<1,x,val);
	else addtre(p<<1|1,x,val);
	pushup(p);
}
int main()
{
	int _;sfi(_);
	while(_--)
	{
		sfi(n);
		for(int i=1;i<=n;++i)
		{
			sfi(node[i].x);sfi(node[i].y);sfl(node[i].val);
			hashx[i]=node[i].x;hashy[i]=node[i].y;
		}
		sort(hashx+1,hashx+1+n);
		sort(hashy+1,hashy+1+n);
		for(int i=1;i<=n;++i)
		{
			node[i].x=lower_bound(hashx+1,hashx+1+n,node[i].x)-hashx;
			node[i].y=lower_bound(hashy+1,hashy+1+n,node[i].y)-hashy;
		}
		sort(node+1,node+1+n);
		LL ans=-1e18;
		for(int i=1;i<=n;++i)
		{
			if(i!=1&&node[i].y==node[i-1].y)continue;
			build(1,1,n);
			for(int j=i;j<=n;)
			{
				int k=j;
				while(k<=n&&node[j].y==node[k].y)
				{
					addtre(1,node[k].x,node[k].val);
					k++;
				}
				j=k;
				ans=max(ans,dat(1));
			}
		}
		printf("%lld\n",ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值