hdu6638 Snowy Smile 离散 扫描线 线段树

90 篇文章 0 订阅
12 篇文章 0 订阅

题意


给n个带权点,求最大子矩阵和

做法


没想到n^2log的做法,老年选手预兆
考虑离散,枚举矩形的下边界,然后一行一行加入点,用线段树维护最大子段和
每加入一整行我们就在线段树中查询、更新答案

我的代码常数特别大,但是能过,这就很奇妙。。

代码


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>

#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define max(x,y) ((x)>(y)?(x):(y))

typedef long long LL;
const int N=5005;
const int INF=(1e9)+7;

struct pos {int x,y,w;} p[N];

std:: vector <int> vec[N];

LL ls[N<<2],rs[N<<2],mx[N<<2],s[N<<2];
int sx[N],sy[N];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void pushUp(int now) {
	s[now]=s[now<<1]+s[now<<1|1];
	ls[now]=max(ls[now<<1],s[now<<1]+ls[now<<1|1]);
	rs[now]=max(rs[now<<1|1],s[now<<1|1]+rs[now<<1]);
	mx[now]=max(max(mx[now<<1|1],mx[now<<1]),rs[now<<1]+ls[now<<1|1]);
}

void modify(int now,int tl,int tr,int x,int v) {
	if (tl==tr) {
		s[now]+=v,mx[now]+=v;
		ls[now]+=v,rs[now]+=v;
		return ;
	}
	int mid=(tl+tr)>>1;
	if (x<=mid) modify(now<<1,tl,mid,x,v);
	else modify(now<<1|1,mid+1,tr,x,v);
	pushUp(now);
}

void build(int now,int tl,int tr) {
	mx[now]=s[now]=ls[now]=rs[now]=0;
	if (tl==tr) return ;
	int mid=(tl+tr)>>1;
	build(now<<1,tl,mid); build(now<<1|1,mid+1,tr);
}

bool cmp(pos a,pos b) {
	return (a.x!=b.x)?(a.x<b.x):(a.y<b.y);
}

int main(void) {
	freopen("data.in","r",stdin);
	freopen("myp.out","w",stdout);
	for (int T=read();T--;) {
		int n=read();
		rep(i,1,n) {
			p[i].x=read(),p[i].y=read();
			sx[i]=p[i].x,sy[i]=p[i].y;
			p[i].w=read();
		}
		std:: sort(sx+1,sx+n+1);
		std:: sort(sy+1,sy+n+1);
		int tx=std:: unique(sx+1,sx+n+1)-sx-1;
		int ty=std:: unique(sy+1,sy+n+1)-sy-1;
		rep(i,1,n) {
			p[i].x=std:: lower_bound(sx+1,sx+tx+1,p[i].x)-sx;
			p[i].y=std:: lower_bound(sy+1,sy+ty+1,p[i].y)-sy;
		}
		// std:: sort(p+1,p+n+1,cmp);
		rep(i,1,tx) vec[i].clear();
		rep(i,1,n) vec[p[i].x].push_back(i);
		LL ans=0;
		rep(i,1,tx) {
			build(1,1,ty);
			rep(j,i,tx) {
				for (int k=0,size=vec[j].size();k<size;++k) {
					int tmp=vec[j][k];
					modify(1,1,ty,p[tmp].y,p[tmp].w);
				}
				(mx[1]>ans)?(ans=mx[1]):0;
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值