2019 Multi-University Training Contest 6 Snowy Smile (最大字段和变形)

题意:

求一个子矩阵要求其矩阵内的合最大。

题解:

正常的求最大子矩阵的复杂度是O(n^3) 

对于这一题说复杂度过不去,注意到这个题总共只有2000个点关键点在与这里优化

最大子矩阵可以压缩矩阵变成最大字段和问题

然后可以通过带修改的最大字段和维护这2000个点,复杂度就变成了了O(n^2logn)

将算出每一列的合的操作 用待修改的最大字段和的线段树维护。

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <set>
  7 #include <iostream>
  8 #include <map>
  9 #include <stack>
 10 #include <string>
 11 #include <vector>
 12 #define  pi acos(-1.0)
 13 #define  eps 1e-9
 14 #define  fi first
 15 #define  se second
 16 #define  rtl   rt<<1
 17 #define  rtr   rt<<1|1
 18 #define  bug         printf("******\n")
 19 #define  mem(a,b)    memset(a,b,sizeof(a))
 20 #define  name2str(x) #x
 21 #define  fuck(x)     cout<<#x" = "<<x<<endl
 22 #define  f(a)        a*a
 23 #define  sf(n)       scanf("%d", &n)
 24 #define  sff(a,b)    scanf("%d %d", &a, &b)
 25 #define  sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
 26 #define  sffff(a,b,c,d) scanf("%d %d %d %d", &a, &b, &c, &d)
 27 #define  pf          printf
 28 #define  FRE(i,a,b)  for(i = a; i <= b; i++)
 29 #define  FREE(i,a,b) for(i = a; i >= b; i--)
 30 #define  FRL(i,a,b)  for(i = a; i < b; i++)+
 31 #define  FRLL(i,a,b) for(i = a; i > b; i--)
 32 #define  FIN         freopen("data.txt","r",stdin)
 33 #define  gcd(a,b)    __gcd(a,b)
 34 #define  lowbit(x)   x&-x
 35 #define rep(i,a,b) for(int i=a;i<b;++i)
 36 #define per(i,a,b) for(int i=a-1;i>=b;--i)
 37 using namespace std;
 38 typedef long long  LL;
 39 typedef unsigned long long ULL;
 40 const int maxn = 4000 + 7;
 41 const int maxm = 8e6 + 10;
 42 const int mod = 1e9 + 7;
 43 const int INF = 0x3f3f3f3f;
 44 int T, n;
 45 LL s[maxn], x[maxn], y[maxn], a[maxn], b[maxn], w[maxn], mp[maxn][maxn];
 46 struct Segtree {
 47     LL maxx, vl, vr, sum, fg;
 48 
 49 } Tree[maxn << 3];
 50 void updata ( int rt ) {
 51     Tree[rt].maxx = max ( Tree[rtl].maxx, max ( Tree[rtr].maxx, Tree[rtl].vr + Tree[rtr].vl ) );
 52     Tree[rt].sum = Tree[rtl].sum + Tree[rtr].sum;
 53     Tree[rt].vl = max ( Tree[rtl].vl, Tree[rtl].sum + Tree[rtr].vl );
 54     Tree[rt].vr = max ( Tree[rtr].vr, Tree[rtr].sum + Tree[rtl].vr );
 55 }
 56 void build ( int l, int r, int rt ) {
 57     Tree[rt].fg = true;
 58     if ( l == r ) {
 59         Tree[rt].sum = s[l];
 60         Tree[rt].maxx = s[l];
 61         Tree[rt].vl = s[l];
 62         Tree[rt].vr = s[l];
 63         return ;
 64     }
 65     int mid = ( l + r ) >> 1;
 66     build ( l, mid, rtl );
 67     build ( mid + 1, r, rtr );
 68     updata ( rt );
 69 }
 70 void add ( int l, int r, int rt, int pos, int to ) {
 71     if ( l > pos || r < pos ) return ;
 72     if ( l == r ) {
 73         Tree[rt].sum += to;
 74         Tree[rt].maxx += to;
 75         Tree[rt].vl += to;
 76         Tree[rt].vr += to;
 77         return ;
 78     }
 79     int mid = ( l + r ) >> 1;
 80     add ( l, mid, rtl, pos, to );
 81     add ( mid + 1, r, rtr, pos, to );
 82     updata ( rt );
 83 }
 84 Segtree query ( int l, int r, int rt, int sa, int se ) {
 85     if ( sa <= l && r <= se ) return Tree[rt];
 86     int mid = ( l + r ) >> 1;
 87     if ( sa > mid ) return query ( mid + 1, r, rtr, sa, se );
 88     if ( se <= mid ) return query ( l, mid, rtl, sa, se );
 89     Segtree t, lson, rson;
 90     lson = query ( l, mid, rtl, sa, se );
 91     rson = query ( mid + 1, r, rtr, sa, se );
 92     t.vl = max ( lson.vl, lson.sum + rson.vl );
 93     t.vr = max ( rson.vr, lson.vr + rson.sum );
 94     t.maxx = max ( lson.vr + rson.vl, max ( lson.maxx, rson.maxx ) );
 95     return t;
 96 }
 97 vector<LL>v[maxn];
 98 int main() {
 99 //    FIN;
100     sf ( T );
101     while ( T-- ) {
102         sf ( n );
103         for ( int i = 1 ; i <= n ; i++ ) {
104             scanf ( "%lld%lld%lld", &x[i], &y[i], &w[i] );
105             a[i] = x[i], b[i] = y[i];
106             v[i].clear();
107         }
108         sort ( a + 1, a + 1 + n ), sort ( b + 1, b + 1 + n );
109         int len1 = unique ( a + 1, a + 1 + n ) - a - 1;
110         int len2 = unique ( b + 1, b + 1 + n ) - b - 1;
111         for ( int i = 0 ; i <= n ; i++ ) for ( int j = 0 ; j <= n ; j++ ) mp[i][j] = 0;
112         for ( int i = 1 ; i <= n ; i++ ) {
113             x[i] = lower_bound ( a + 1, a + 1 + len1, x[i] ) - a;
114             y[i] = lower_bound ( b + 1, b + 1 + len2, y[i] ) - b;
115             mp[y[i]][x[i]] += w[i];
116         }
117         for ( int i = 1 ; i <= n ; i++ )
118             for ( int j = 1 ; j <= n ; j++ )
119                 if ( mp[i][j] )  v[i].push_back ( j );
120         LL ans = 0;
121         for ( int i = 1 ; i <= n ; i++ ) {
122             for ( int j = 1 ; j <= n ; j++ ) s[j] = mp[i][j];
123             build ( 1, n, 1 );
124             ans = max ( ans, query ( 1, n, 1, 1, n ).maxx );
125             for ( int j = i + 1 ; j <= n ; j++ ) {
126                 for ( int k = 0 ; k < v[j].size() ; k++ ) {
127                     add ( 1, n, 1, v[j][k], mp[j][v[j][k]] );
128                 }
129                 ans = max ( ans, query ( 1, n, 1, 1, n ).maxx );
130             }
131         }
132         printf ( "%lld\n", ans );
133     }
134     return 0;
135 }
View Code

 

转载于:https://www.cnblogs.com/qldabiaoge/p/11318738.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值