#include <iostream>
#include <math.h>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <iomanip>
#include <set>
#include <bitset>
#include <unordered_map>
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using piii = tuple<int,int,int>;
#define f first
#define s second
#define endl '\n'
#define all(x) begin(x),end(x)
#define m_p make_pair
int const N = 2e3+10;
int const INF = 1e9+10;
int tb[N][N];
bool vis[N][N];
struct Node{
int val;
Node* l;
Node* r;
Node() : val(0),l(0),r(0) {}
};
typedef Node* pnode;
int si;
vector<pnode> tree;
void builder(pnode &node,int l,int r){
node = new Node();
if(l != r){
int md = l+(r-l)/2;
builder(node->l,l,md);
builder(node->r,md+1,r);
}
}
void builder(){
tree.emplace_back(nullptr);
builder(tree.back(),1,si);
}
void update(pnode &node,pnode time,int l,int r,int idx,int val){
node = new Node(*time);
if(l == r && l == idx) node->val += val;
else if(l > idx || r < idx) return;
else{
int md = l+(r-l)/2;
update(node->l,time->l,l,md,idx,val);
update(node->r,time->r,md+1,r,idx,val);
node->val = node->l->val+node->r->val;
}
}
void update(int time,int idx,int val){
tree.emplace_back(nullptr);
update(tree.back(),tree[time],1,si,idx,val);
}
int query(pnode L,pnode R,int l,int r,int ql,int qr){
if(l >= ql && r <= qr) return R->val-L->val;
else if(l > qr || r < ql) return 0;
else{
int md = l+(r-l)/2;
int q1 = query(L->l,R->l,l,md,ql,qr);
int q2 = query(L->r,R->r,md+1,r,ql,qr);
return q1+q2;
}
}
int query(int timel,int timer,int ql,int qr){
return query(tree[timel],tree[timer],1,si,ql,qr);
}
void extend(){
tree.emplace_back(new Node(*tree.back()));
}
void print(pnode node,int l,int r){
if(l == r) cout << node->val << " ";
else{
int md = l+(r-l)/2;
print(node->l,l,md);
print(node->r,md+1,r);
}
}
void print(int time){
print(tree[time],1,si);
cout << endl;
}
struct INFO{
int sum = 0;
int minpos = 0;
int maxpos = 0;
};
bool comp(INFO const &a,INFO const &b){
return a.minpos < b.minpos;
}
vector<INFO> vc;
vector<pii> mov = {{0,1},{1,0},{0,-1},{-1,0}};
vector<int> pos = {0};
INFO cur;
int r,c;
int dp[N][N];
void dfs(int i,int j){
cur.sum += tb[i][j];
cur.minpos = min(cur.minpos,j);
cur.maxpos = max(cur.maxpos,j);
for(auto [a,b]:mov){
int ny = i+a;
int nx = j+b;
if(ny <= 0 || ny > r) continue;
if(nx <= 0 || nx > c) continue;
if(vis[ny][nx]) continue;
if(tb[ny][nx] == -1) continue;
vis[ny][nx] = 1;
dfs(ny,nx);
}
}
int cost(int l,int r){
return query(pos[l],pos[r],r,si);
}
void dvc(int i,int l,int r,int rl,int rr){
pii best = {-INF,-1};
int md = l+(r-l)/2;
for(int j{rl};j <= min(md,rr);j++){
int val = dp[i-1][j]+cost(j,md);
best = max(best,{val,j});
}
dp[i][md] = best.f;
if(l == r) return;
dvc(i,l,md,rl,best.s);
dvc(i,md+1,r,best.s,rr);
}
int main(){
ios_base::sync_with_stdio(0);cin.tie(0);
cin >> r;
cin >> c;
si = c;
for(int i{1};i <= r;i++){
for(int j{1};j <= c;j++){
char ch;cin >> ch;
if(ch == '.') tb[i][j] = -1;
else tb[i][j] = ch-'0';
}
}
for(int i{1};i <= r;i++){
for(int j{1};j <= c;j++){
if(tb[i][j] == -1 || vis[i][j]) continue;
vis[i][j] = 1;
cur.sum = 0;
cur.minpos = INF;
cur.maxpos = 0;
dfs(i,j);
vc.emplace_back(cur);
}
}
sort(all(vc),comp);
builder();
int amo = vc.size();
int p1 = 0;
for(int i{1};i <= c;i++){
while(p1 < amo && vc[p1].minpos <= i){
update(tree.size()-1,vc[p1].maxpos,vc[p1].sum);
p1++;
}
pos.emplace_back(tree.size()-1);
}
// for(int i{1};i <= c;i++){
// cout << pos[i] << endl;
// print(pos[i]);
// }
// cout << cost(1,5) << endl;
// cout << cost(1,3) << endl;
for(int i{2};i <= c;i++){
dp[0][i] = -INF;
}
for(int i{1};i <= c;i++){
dvc(i,1,c,0,c);
int maxi = 0;
for(int j{1};j <= c;j++) maxi = max(maxi,dp[i][j]);//, cout << dp[i][j] << " ";
// cout << endl;
cout << maxi << endl;
}
}