This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e3;
char st[MAXN + 7][MAXN + 7];
int a[MAXN + 7];
long long table[MAXN + 7][MAXN + 7];
int N, M;
class SegmentTree {
private:
	pair<int, int> tree[4 * MAXN + 7];
	pair<int, int> merge (pair<int, int> x, pair<int, int> y) {
		if (x.first <= y.first) {
			return x;
		}
		return y;
	}
	void upd (int ss, int se, int si, int ui, int uv) {
		if (ss == se) {
			tree[si] = {uv, ui};
		}
		else {
			int mid = (ss + se) >> 1;
			if (ui <= mid) {
				upd(ss, mid, si * 2, ui, uv);
			}
			else {
				upd(mid + 1, se, si * 2 + 1, ui, uv);
			}
			tree[si] = merge(tree[si * 2], tree[si * 2 + 1]);
		}
	}
	pair<int, int> qry (int ss, int se, int si, int qs, int qe) {
		if (ss > qe || qs > se) {
			return {MAXN + 7, 0};
		}
		if (qs <= ss && se <= qe) {
			return tree[si];
		}
		int mid = (ss + se) >> 1;
		return merge(qry(ss, mid, si * 2, qs, qe), qry(mid + 1, se, si * 2 + 1, qs, qe));
	}
public:
	void update (int ui, int uv) {
		upd(1, M, 1, ui, uv);
	}
	int query (int qs, int qe) {
		return qry(1, M, 1, qs, qe).second;
	}
}
segtree;
long long calc (int i, int j) {
	return (i * 1LL * (i + 1)) * (j * 1LL * (j + 1)) / 4;
}
long long solve (int ss, int se) {
	if (ss > se) {
		return 0;
	}
	if (ss == se) {
		// cerr << ss << " " << ss << " " << se << " " << table[se - ss + 1][a[ss]] << "\n";
		// return table[se - ss + 1][a[ss]];
		// cerr << ss << " " << ss << " " << se << " " << calc(se - ss + 1, a[ss]) << "\n";
		return calc(se - ss + 1, a[ss]);
	}
	int mid = segtree.query(ss, se);
	long long ansl = solve(ss, mid - 1);
	long long ansr = solve(mid + 1, se);
	long long ans = ansl + ansr;
	// ans += table[se - ss + 1][a[mid]];
	ans += table[se - ss + 1][a[mid]];
	ans -= table[mid - 1 - ss + 1][a[mid]];
	ans -= table[se - (mid + 1) + 1][a[mid]];
	// cerr << ss << " " << mid << " " << se << " " << ans << "\n";
	return ans;
}
int main () {
	table[1][1] = 1;
	for (int i = 1; i <= MAXN; i++) {
		for (int j = 1; j <= MAXN; j++) {
			table[i][j] = table[i - 1][j] + calc(i, j);
		}
	}
	cin >> N >> M;
	for (int i = 1; i <= N; i++) {
		scanf("%s", st[i] + 1);
	}
	long long ans = 0;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			if (st[i][j] == '#') {
				a[j] = 0;
			}
			else {
				a[j]++;
			}
			segtree.update(j, a[j]);
		}
		ans += solve(1, M);
	}
	cout << ans << "\n";
	
	return 0;
}
Compilation message (stderr)
strah.cpp: In function 'int main()':
strah.cpp:117:8: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
   scanf("%s", st[i] + 1);
   ~~~~~^~~~~~~~~~~~~~~~~| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |