好个差分!
题意:
给定一个
n
×
w
n\times w
n × w 矩形, 还给定n个数组, 每个数组的长度都小于等于w, 所以每个长度小于w的数组都可以在一行内左右滑动 现求在保证所有数组都在矩形范围内滑动的情况下, 该矩形的每一列的最大值
数据范围:
n
≤
1000000
n \leq 1000000
n ≤ 1 0 0 0 0 0 0
前置技能: 线段树+差分
Tutorial: 模拟了几个例子后发现, 每列的值只可能在数列的区间内取值, 可以想到要维护每个数组的区间最大, 这里用的线段树, 我第一种写法是针对每一列的每个位置都求一遍区间最大, degug的时候发现, 当
l
e
n
∗
2
<
w
len *2 < w
l e n ∗ 2 < w 的时候, 中间有一段的最大值是整个数组的最大值, 所以又想到用差分维护答案, 这种情况可以区间修改, 当然也可以用另一个线段树维护, 不是这种情况的就只有暴力修改了
本题还遇到两个小小的波折, 其中一个是针对最大值与0取最大值, 还有一个就是线段树清零(build的时候已经覆盖了原来的数据不用清零, 清零会T)
#include <bits/stdc++.h>
using namespace std;
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (int i = (a); i >= (b); --i)
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rof(i, a, b) for (int i = (a); i > (b); --i)
#define oo 0x3f3f3f3f
#define ll long long
#define db double
#define eps 1e-8
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl;
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair<int, int>
int nxt ( )
{
int ret;
scanf ( "%d" , & ret) ;
return ret;
}
const int maxn = 1e6 + 10 ;
ll ans[ maxn] ;
int n, w;
int a[ maxn] ;
struct seg
{
#define le o << 1
#define ri o << 1 | 1
#define lson t[le]
#define rson t[ri]
struct node
{
int l, r, val;
} t[ maxn * 4 ] ;
void update ( int o)
{
assert ( o <= maxn * 4 ) ;
t[ o] . val = max ( lson. val, rson. val) ;
}
void build ( int o, int l, int r)
{
assert ( o <= maxn * 4 ) ;
t[ o] . l = l, t[ o] . r = r;
if ( l == r)
{
assert ( scanf ( "%d" , & t[ o] . val) == 1 ) ;
return ;
}
int mid = l + r >> 1 ;
build ( le, l, mid) ;
build ( ri, mid + 1 , r) ;
update ( o) ;
}
void clear ( )
{
met ( t, 0 ) ;
}
int query ( int o, int l, int r)
{
assert ( o <= maxn * 4 ) ;
assert ( l <= r) ;
if ( l <= t[ o] . l && r >= t[ o] . r)
return t[ o] . val;
int mid = t[ o] . l + t[ o] . r >> 1 ;
if ( mid >= r)
return query ( le, l, r) ;
else if ( mid < l)
return query ( ri, l, r) ;
else
return max ( query ( le, l, mid) , query ( ri, mid + 1 , r) ) ;
}
} seg1;
signed main ( )
{
n = nxt ( ) , w = nxt ( ) ;
_rep ( i, 1 , n)
{
int len = nxt ( ) ;
seg1. build ( 1 , 1 , len) ;
if ( len * 2 < w)
{
_rep ( i, 1 , len)
{
ll pre_max = max ( seg1. query ( 1 , 1 , i) , 0 ) , suf_max = max ( seg1. query ( 1 , len - i + 1 , len) , 0 ) ;
ans[ i] + = pre_max;
ans[ i + 1 ] - = pre_max;
ans[ w - i + 1 ] + = suf_max;
ans[ w - i + 2 ] - = suf_max;
}
ll all_max = max ( 0 , seg1. query ( 1 , 1 , len) ) ;
ans[ len + 1 ] + = all_max;
ans[ w - len + 1 ] - = all_max;
}
else
{
_rep ( i, 1 , w)
{
int r = i, l = i - ( w - len) ;
ll val = seg1. query ( 1 , max ( l, 1 ) , min ( r, len) ) ;
if ( r > len || l < 1 ) val = max ( ( ll) 0 , val) ;
ans[ i] + = val;
ans[ i + 1 ] - = val;
}
}
}
_rep ( i, 1 , w)
{
ans[ i] + = ans[ i - 1 ] ;
cout << ans[ i] << " " ;
}
cout << endl;
}