2019 Multi-University Training Contest 6

被刻印的时光 ゝ 提交于 2019-11-27 11:12:00

HDU 6638-Snowy Smile

Time Limit: 4000/4000 MS (Java/Others)    Memory Limit: 524288/524288 K 


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 wiwi 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(1T100), denoting the number of test cases.

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

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

It is guaranteed that n10000.
 

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
 
题目大意就是一个坐标系有好多数值,有正有负,然后选定一个矩形区域,使得该区域内和最大,输出该和。
 
注意到最多只有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 }
神奇的代码

 

 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!