Snowy Smile HDU - 6638 利用線段樹區間合併 求最大子段和

Snowy Smile

Time Limit: 4000/4000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 2429    Accepted Submission(s): 774


 

Problem Description

There are n pirate chests buried in Byteland, labeled by 1,2,…,n. The i-th chest's location is (xi,yi), and its value is wi, wi can be negative since the pirate can add some poisonous gases into the chest. When you open the i-th pirate chest, you will get wi value.

You want to make money from these pirate chests. You can select a rectangle, the sides of which are all paralleled to the axes, and then all the chests inside it or on its border will be opened. Note that you must open all the chests within that range regardless of their values are positive or negative. But you can choose a rectangle with nothing in it to get a zero sum.

Please write a program to find the best rectangle with maximum total value.

 

Input

The first line of the input contains an integer T(1≤T≤100), denoting the number of test cases.

In each test case, there is one integer n(1≤n≤2000) in the first line, denoting the number of pirate chests.

For the next n lines, each line contains three integers xi,yi,wi(−109≤xi,yi,wi≤109), denoting each pirate chest.

It is guaranteed that ∑n≤10000.

 

Output

For each test case, print a single line containing an integer, denoting the maximum total value.

 

Sample Input

2 4 1 1 50 2 1 50 1 2 50 2 2 -500 2 -1 1 5 -1 1 1

 

Sample Output

100 6

 

 

題意:給你n個點的座標(x,y),以及該點的價值w,讓你找一個平行於xy軸的矩陣,使得該矩陣包含的價值最大,輸出該價值。

思路:最大子矩陣和,由於座標過大,但只有2000個點可進行離散化。

2種會T的方法:

1.枚舉矩陣的左上角,左下角,右上角,右下角,維護一個最大值。時間複雜度 :O(N^4)

2.DP,降維轉化爲最子字段和。時間複雜度:O(N^3)

正解:這是在2方法上的改進,暴力枚舉區間的左端點x1和右端點x2複雜度是O(N^2),右端點枚舉到x2時,把x座標是x2的點插入到線段樹,複雜度是O(logN),線段樹查詢當前最大子段和,複雜度是O(1)。總體時間複雜度爲O(N^2*logN);

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2010;
int x[maxn],y[maxn],cntx,cnty,n;
struct Node{
	int l;
	int r;
	ll left;
	ll right;
	ll sum;
	ll maxx; 
}tree[maxn<<2];
struct node{
	int x;
	int y;
	ll w; 
}a[maxn];
bool cmp(node xx,node yy)
{
	return xx.x<yy.x;
}
void pushup(int cur)
{
	tree[cur].sum=tree[cur<<1].sum+tree[cur<<1|1].sum;
	tree[cur].left=max(tree[cur<<1].left,tree[cur<<1].sum+tree[cur<<1|1].left);
	tree[cur].right=max(tree[cur<<1|1].right,tree[cur<<1|1].sum+tree[cur<<1].right);
	tree[cur].maxx=max(tree[cur<<1].maxx,tree[cur<<1|1].maxx);
	tree[cur].maxx=max(tree[cur].maxx,tree[cur<<1].right+tree[cur<<1|1].left);
}
void build(int l,int r,int cur)
{
	tree[cur].l=l;
	tree[cur].r=r;
	tree[cur].left=0;
	tree[cur].right=0;
	tree[cur].sum=0;
	tree[cur].maxx=0;
	if(l==r) return ;
	int m=(l+r)>>1;
	build(l,m,cur<<1);
	build(m+1,r,cur<<1|1);
}
void update(int tar,ll val,int cur)
{
	if(tree[cur].l==tree[cur].r)
	{
		tree[cur].left+=val;
		tree[cur].right+=val;
		tree[cur].sum+=val;
		tree[cur].maxx+=val;
		return ;
	}
	if(tar<=tree[cur<<1].r) update(tar,val,cur<<1);
	else update(tar,val,cur<<1|1);
	pushup(cur);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		ll ans=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d%d%I64d",&a[i].x,&a[i].y,&a[i].w);
			x[i]=a[i].x;
			y[i]=a[i].y;
		}
		sort(x+1,x+1+n);
		sort(y+1,y+1+n);
		cntx=unique(x+1,x+1+n)-(x+1);
		cnty=unique(y+1,y+1+n)-(y+1);
		for(int i=1;i<=n;i++)
		{
			a[i].x=lower_bound(x+1,x+1+cntx,a[i].x)-x;
			a[i].y=lower_bound(y+1,y+1+cnty,a[i].y)-y;
		}
		sort(a+1,a+1+n,cmp);
		a[0].x=-1;
		for(int i=1;i<=n;i++)
		{
			if(a[i].x!=a[i-1].x)
			{
				build(1,cnty,1);
				for(int j=i;j<=n;j++)
				{
					update(a[j].y,a[j].w,1);
					if(a[j].x==a[j+1].x&&j!=n) continue;
					ans=max(ans,tree[1].maxx);
				}
			}
		}
		printf("%I64d\n",ans);
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章