2019 Multi-University Training Contest 6
HDU 6638-Snowy Smile
Time Limit: 4000/4000 MS (Java/Others) Memory Limit: 524288/524288 K
Problem Description
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
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
Sample Input
Sample Output
题目大意就是一个坐标系有好多数值,有正有负,然后选定一个矩形区域,使得该区域内和最大,输出该和。
注意到最多只有2000个点,我们将坐标离散化后实际上就是一个矩形,然后找出和最大的子矩形。
这个问题有O(n3)的做法,就是枚举两行,然后将两行的每一列都压成一个数求一下最大的子区间和就好了。
但这里n最大为2000会TLE。
我们知道线段树是可以来维护区间的最大子区间和的,我们固定一行y1,枚举另一行y2从y1到ymax,每枚举一行我们将这一行的数xi加到线段树对应位置上,那我们可以O(1)知道答案。
但问题出在更新上,每枚举一行更新的复杂度岂不是要nlogn??
我们注意到如果离散后矩阵大小是2000*2000,而因为最多只有两千个点,那么每行只有一个数,我们其实对于每一行的更新只用更新一次,只要logn,如果这一行有多个数,那么行数也会相应的减少,而不会出现nlogn的情况
平均下来其实只要logn,总复杂度是n2logn。
最大和的子区间要不就是左儿子的子区间,要不就是右儿子的子区间,要不就是横跨左右儿子的子区间。
用线段树来维护区间的最大子区间和,维护四个量。
以该区间左端点为起始点向右延伸的最大子区间和ls
以该区间右端点为起始点向左延伸的最大子区间和rs
该区间的和s
该区间的最大子区间和ms
更新的话,s就左右儿子的s相加。
ls则是 左儿子的ls 与 左儿子的区间和s+右儿子的ls 中的最大值
rs则是 右儿子的rs 与 右儿子的区间和s+左儿子的rs 中的最大值
ms则是 左儿子的ms 与 右儿子的ms 与左儿子的rs+右儿子的ls 中的最大值
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <vector> 7 #include <cstdlib> 8 #include <cmath> 9 #include <string> 10 #define fo(i,a,b) for (int i=(a);i<=(b);++i) 11 #define fod(i,a,b) for (int i=(a);i>=(b);--i) 12 #define rep(i,a,b) for (int i=(a);i<(b);++i) 13 #define repd(i,a,b) for (int i=(a);i>(b);--i) 14 #define MAX(a,b) (((a)>(b)?(a):(b))) 15 #define N 2005 16 typedef long long LL; 17 using namespace std; 18 int n,m,t,x_rank[N],y_rank[N],x_size,y_size,x[N],y[N],xx,yy,biao[N][N],cnt[N]; 19 LL tu[N][N],w[N],ans; 20 bool sign[N][N]; 21 struct Segment_Tree{ 22 #define sth int root,int l,int r 23 #define lsth root<<1,l,mid 24 #define rsth root<<1|1,mid+1,r 25 #define lson root<<1 26 #define rson root<<1|1 27 LL lsum,rsum,asum,sum; 28 }seg[N*4]; 29 inline void readint(int &x){ 30 x=0; 31 char c; 32 int w=1; 33 for (c=getchar();c<'0'||c>'9';c=getchar()) if (c=='-') w=-1; 34 for(;c>='0'&&c<='9';c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); 35 x*=w; 36 } 37 inline void readlong(LL &x){ 38 x=0; 39 char c; 40 LL w=1; 41 for (c=getchar();c<'0'||c>'9';c=getchar()) if (c=='-') w=-1; 42 for(;c>='0'&&c<='9';c=getchar()) x=(x<<3)+(x<<1)+(c^'0'); 43 x*=w; 44 } 45 void build(sth){ 46 if (l==r){ 47 seg[root].sum=seg[root].lsum=seg[root].rsum=seg[root].asum=0; 48 return; 49 } 50 int mid=(l+r)>>1; 51 build(lsth); 52 build(rsth); 53 seg[root].sum=seg[lson].sum+seg[rson].sum; 54 seg[root].lsum=MAX(seg[lson].lsum,seg[lson].sum+seg[rson].lsum); 55 seg[root].rsum=MAX(seg[rson].rsum,seg[rson].sum+seg[lson].rsum); 56 seg[root].asum=MAX(MAX(seg[lson].asum,seg[rson].asum),seg[lson].rsum+seg[rson].lsum); 57 } 58 void updata(sth,int xx,int pos){ 59 if (l==r){ 60 seg[root].sum+=tu[xx][r]; 61 seg[root].lsum+=tu[xx][r]; 62 seg[root].rsum+=tu[xx][r]; 63 seg[root].asum+=tu[xx][r]; 64 return; 65 } 66 int mid=(l+r)>>1; 67 if (pos<=mid) updata(lsth,xx,pos); 68 else updata(rsth,xx,pos); 69 seg[root].sum=seg[lson].sum+seg[rson].sum; 70 seg[root].lsum=MAX(seg[lson].lsum,seg[lson].sum+seg[rson].lsum); 71 seg[root].rsum=MAX(seg[rson].rsum,seg[rson].sum+seg[lson].rsum); 72 seg[root].asum=MAX(MAX(seg[lson].asum,seg[rson].asum),seg[lson].rsum+seg[rson].lsum); 73 } 74 void init(){ 75 ans=0; 76 fo(i,1,x_size) cnt[i]=0; 77 fo(i,1,x_size) fo(j,1,y_size) tu[i][j]=sign[i][j]=0; 78 x_size=y_size=0; 79 readint(n); 80 fo(i,1,n){ 81 readint(x[i]); 82 readint(y[i]); 83 readlong(w[i]); 84 x_rank[++x_size]=x[i]; 85 y_rank[++y_size]=y[i]; 86 } 87 sort(x_rank+1,x_rank+1+x_size); 88 sort(y_rank+1,y_rank+1+y_size); 89 x_size=unique(x_rank+1,x_rank+1+x_size)-(x_rank+1); 90 y_size=unique(y_rank+1,y_rank+1+y_size)-(y_rank+1); 91 fo(i,1,n) { 92 x[i]=lower_bound(x_rank+1,x_rank+1+x_size,x[i])-(x_rank); 93 y[i]=lower_bound(y_rank+1,y_rank+1+y_size,y[i])-(y_rank); 94 tu[x[i]][y[i]]+=w[i]; 95 if (!sign[x[i]][y[i]]){ 96 biao[x[i]][++cnt[x[i]]]=y[i]; 97 sign[x[i]][y[i]]=true; 98 } 99 } 100 } 101 int main(){ 102 readint(t); 103 n=x_size=y_size=0; 104 while (t--){ 105 init(); 106 fo(i,1,x_size){ 107 build(1,1,y_size); 108 fo(j,i,x_size){ 109 fo(k,1,cnt[j]) updata(1,1,y_size,j,biao[j][k]); 110 ans=MAX(ans,seg[1].asum); 111 } 112 } 113 printf("%lld\n",ans); 114 } 115 return 0; 116 }