Problem:
塗りつぶし (Painting)
問題文
JOI くんはお絵かきソフトで遊んでいる．
お絵かきソフトでは，縦
H
行，横
W
列の長方形のマス目に絵を描くことができる．それぞれのマスには色が定められており，色は
1
以上
10
9
以下の整数で表される．
上から
i
行目 (
1 ≦  i ≦ H
)，左から
j
列目 (
1 ≦ j ≦ W
) のマスをマス
(i,j)
と呼ぶ．現在，マス
(i,j)
の色は
A
i,j
である．
マス
(i,j)
から辺で接しているマスへの移動を繰り返し，マス
(i,j)
と色が異なるマスに入ることなく移動できるマスの集まりを，ここでは
マス
(i,j)
の領域
と呼ぶ．
お絵かきソフトには，
塗りつぶし
という機能がある．この機能では，あるマス
(x,y)
(
1 ≦ x ≦ H
，
1 ≦ y ≦ W
) と色
c
(
1 ≦ c ≦ 10
9
) を指定すると，マス
(x,y)
の領域に含まれるマスの色がすべて
c
に変化する．
JOI くんはあるマス
(x,y)
と色
c
を選び，そのマスと色を指定して塗りつぶしをちょうど
1
回使う．塗りつぶしを使った後のマス
(x,y)
の領域に含まれるマスの個数が JOI くんの得点となる．
JOI くんの得点として達成可能な最大値を求めるプログラムを作成せよ．
制約
1 ≦ H ≦ 500
．
1 ≦ W ≦ 500
．
1 ≦ A
i,j
≦ 10
9
(
1 ≦ i ≦ H
，
1 ≦ j ≦ W
)．
入力される値はすべて整数である．
入力
入力は以下の形式で与えられる．
H
W
A
1,1
A
1,2
…
A
1,W
A
2,1
A
2,2
…
A
2,W
:
A
H,1
A
H,2
…
A
H,W
出力
JOI くんの得点として達成可能な最大値を
1
行に出力せよ．
入出力例
入力例 1
4 4
1 2 3 1
2 2 3 1
1 2 3 1
3 3 2 2
出力例 1
9
最初の時点で，マス
(2,2)
の領域に含まれるマスはマス
(1,2), (2,1), (2,2), (3,2)
の
4
個である．そのため，マス
(2,2)
と色
3
を指定して塗りつぶしを使うと，下図のように，これらの
4
マスの色が
3
に変化する．
塗りつぶしを使った後，マス
(2,2)
の領域に含まれるマスはマス
(1,2), (1,3), (2,1), (2,2), (2,3), (3,2), (3,3), (4,1), (4,2)
の
9
個になる．よって，JOI くんの得点は
9
となる．
JOI くんの得点を
10
以上にすることはできないので，
9
を出力する．
入力例 2
2 10
1 2 2 1 3 3 3 3 1 1
1 1 1 1 1 1 1 3 3 3
出力例 2
18
入力例 3
5 5
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
出力例 3
25
情報オリンピック日本委員会
作 『第 22 回日本情報オリンピック JOI 2022/2023 二次予選競技課題』

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FOR(i,l,r) for(ll i=l;i<r;i++)
#define REP(i,n) FOR(i,0,n)
int main(){
    int h,w;cin>>h>>w;
    vector<vector<ll>>a(h,vector<ll>(w));
    REP(i,h)REP(j,w)cin>>a[i][j];
    vector<vector<int>>idx(h,vector<int>(w,-1));
    int cnt=0;
    REP(i,h)REP(j,w)if(idx[i][j]==-1){
        idx[i][j]=cnt;
        using pi=pair<int,int>;
        queue<pi>Q;
        Q.emplace(pi(i,j));
        while(!Q.empty()){
            auto p=Q.front();Q.pop();
            if(p.first&&a[p.first-1][p.second]==a[p.first][p.second]&&idx[p.first-1][p.second]==-1){
                idx[p.first-1][p.second]=cnt;
                Q.emplace(pi(p.first-1,p.second));
            }
            if(p.second&&a[p.first][p.second-1]==a[p.first][p.second]&&idx[p.first][p.second-1]==-1){
                idx[p.first][p.second-1]=cnt;
                Q.emplace(pi(p.first,p.second-1));
            }
            if(p.first+1<h&&a[p.first+1][p.second]==a[p.first][p.second]&&idx[p.first+1][p.second]==-1){
                idx[p.first+1][p.second]=cnt;
                Q.emplace(pi(p.first+1,p.second));
            }
            if(p.second+1<w&&a[p.first][p.second+1]==a[p.first][p.second]&&idx[p.first][p.second+1]==-1){
                idx[p.first][p.second+1]=cnt;
                Q.emplace(pi(p.first,p.second+1));
            }
        }
        cnt++;
    }
    vector<int>size(cnt),color(cnt);
    REP(i,h)REP(j,w)size[idx[i][j]]++,color[idx[i][j]]=a[i][j];
    vector<vector<int>>E(cnt);
    REP(i,h)REP(j,w){
        if(i&&idx[i-1][j]!=idx[i][j]){
            E[idx[i][j]].emplace_back(idx[i-1][j]);
            E[idx[i-1][j]].emplace_back(idx[i][j]);
        }
        if(j&&idx[i][j-1]!=idx[i][j]){
            E[idx[i][j]].emplace_back(idx[i][j-1]);
            E[idx[i][j-1]].emplace_back(idx[i][j]);
        }
    }
    int ans=0;
    REP(i,cnt){
        sort(E[i].begin(),E[i].end());
        E[i].erase(unique(E[i].begin(),E[i].end()),E[i].end());
        map<int,int>memo;
        for(auto j:E[i])memo[color[j]]+=size[j];
        ans=max(ans,size[i]);
        for(auto[k,v]:memo)ans=max(ans,size[i]+v);
    }
    cout<<ans<<endl;
    return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 21720
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001




#define SIZE 505*505

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];

int H,W;
int A[505][505];
int d_row[4] = {-1,0,0,1},d_col[4] = {0,-1,1,0};
int value[SIZE];
vector<int> V[SIZE];

bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}

int getIndex(int row,int col){

	return row*W + col;
}

int main(){

	scanf("%d %d",&H,&W);

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			scanf("%d",&A[row][col]);
		}
	}

	N = H*W;

	for(int i = 0; i < N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			int from = getIndex(row,col);

			for(int i = 0; i < 4; i++){

				int adj_row = row+d_row[i];
				int adj_col = col+d_col[i];
				if(!rangeCheck(adj_row,adj_col)||A[row][col] != A[adj_row][adj_col])continue;

				int to = getIndex(adj_row,adj_col);

				unite(from,to);
			}
		}
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			int from = getIndex(row,col);

			for(int i = 0; i < 4; i++){

				int adj_row = row+d_row[i];
				int adj_col = col+d_col[i];
				if(!rangeCheck(adj_row,adj_col))continue;

				int to = getIndex(adj_row,adj_col);

				//辺で接するグループの組合せを記録しておく
				if(A[row][col] != A[adj_row][adj_col]){

					V[get_boss(from)].push_back(get_boss(to));
				}
			}
		}
	}

	int ans = 0;

	vector<int> vec;

	for(int i = 0; i < N; i++){
		if(i != get_boss(i))continue;

		vec.push_back(i);

		chmax(ans,num_member[i]);
		int tmp_row = i/W;
		int tmp_col = i%W;
		value[i] = A[tmp_row][tmp_col]; //そのグループの数字

		if(V[i].size() == 0)continue;

		sort(V[i].begin(),V[i].end());
		V[i].erase(unique(V[i].begin(),V[i].end()),V[i].end());
	}

	for(int i = 0; i < vec.size(); i++){

		//隣接するグループの数字ごとに、総和を集計する
		map<int,int> MAP;
		for(int k = 0; k < V[vec[i]].size(); k++){

			MAP[value[V[vec[i]][k]]] += num_member[V[vec[i]][k]];
		}

		for(auto at = MAP.begin(); at != MAP.end(); at++){

			int work = num_member[vec[i]] + at->second;
			chmax(ans,work);
		}
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 25204
final_rank: 4

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) { return (ull)rng() % B; }

int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int h, w;
    cin >> h >> w;
    vector<vector<int>> a(h, vector<int>(w));
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            cin >> a[i][j];
        }
    }
    vector<vector<int>> idx(h, vector<int>(w, -1));
    vector<int> cnt(h * w);
    queue<pair<int, int>> q;
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            if (idx[i][j] == -1) {
                q.push({i, j});
                idx[i][j] = i * w + j;
            }
            while (q.size()) {
                auto p = q.front();
                q.pop();
                int x = p.first, y = p.second;
                cnt[idx[x][y]] += 1;
                for (int k = 0; k < 4; ++k) {
                    int nx = x + dx[k];
                    int ny = y + dy[k];
                    if (0 <= nx and nx < h and 0 <= ny and ny < w and a[nx][ny] == a[x][y] and idx[nx][ny] == -1) {
                        idx[nx][ny] = idx[x][y];
                        q.push({nx, ny});
                    }
                }
            }
        }
    }
   
    int res = 0;
    vector<vector<bool>> used(h, vector<bool>(w));
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            if (used[i][j]) continue;
            map<int, int> mp;
            set<int> st;
            q.push({i, j});
            used[i][j] = true;
            while (q.size()) {
                auto p = q.front();
                q.pop();
                int x = p.first, y = p.second;
                for (int k = 0; k < 4; ++k) {
                    int nx = x + dx[k];
                    int ny = y + dy[k];
                    if (0 <= nx and nx < h and 0 <= ny and ny < w) {
                        if (a[nx][ny] != a[x][y]) {
                            int id = idx[nx][ny];
                            int col = a[nx][ny];
                            if (st.find(id) == st.end()) {
                                st.insert(id);
                                mp[col] += cnt[id];
                            }
                        } else if (!used[nx][ny]) {
                            used[nx][ny] = true;
                            q.push({nx, ny});
                        }
                    }
                }
            }
            res = max(res, cnt[idx[i][j]]);
            for (auto p : mp) {
                res = max(res, p.second + cnt[idx[i][j]]);
            }
        }
    }
    cout << res << endl;
}
accuracy: 1
time_ms: 100
memory_kb: 17776
final_rank: 1

code_snippet: #line 1 "/opt/library/template.hpp"
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using i64 = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
using f128 = __float128;

template <class T>
constexpr T infty = 0;
template <>
constexpr int infty<int> = 1'000'001'000;
template <>
constexpr ll infty<ll> = ll(infty<int>) * infty<int> * 2;
template <>
constexpr u32 infty<u32> = infty<int>;
template <>
constexpr u64 infty<u64> = infty<ll>;
template <>
constexpr i128 infty<i128> = i128(infty<ll>) * infty<ll>;
template <>
constexpr double infty<double> = infty<ll>;
template <>
constexpr long double infty<long double> = infty<ll>;
#define inf infty<ll>

using pi = pair<ll, ll>;
using vi = vector<ll>;
using vvi = vector<vector<ll>>;
template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;
template <class T>
using vvvc = vector<vvc<T>>;
template <class T>
using vvvvc = vector<vvvc<T>>;
template <class T>
using vvvvvc = vector<vvvvc<T>>;
template <class T>
using pq = priority_queue<T>;
template <class T>
using pqg = priority_queue<T, vector<T>, greater<T>>;

#define vv(type, name, h, ...) \
  vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define vvv(type, name, h, w, ...)   \
  vector<vector<vector<type>>> name( \
      h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...)       \
  vector<vector<vector<vector<type>>>> name( \
      a, vector<vector<vector<type>>>(       \
             b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))

#define rep1(a) for (ll _ = 0; _ < (ll)(a); ++_)
#define rep2(i, a) for (ll i = 0; i < (ll)(a); ++i)
#define rep3(i, a, b) for (ll i = a; i < (ll)(b); ++i)
#define rep4(i, a, b, c) for (ll i = a; i < (ll)(b); i += (c))
#define rrep1(a) for (ll i = (a)-1; i >= (ll)(0); --i)
#define rrep2(i, a) for (ll i = (a)-1; i >= (ll)(0); --i)
#define rrep3(i, a, b) for (ll i = (b)-1; i >= (ll)(a); --i)
#define rrep4(i, a, b, c) for (ll i = (b)-1; i >= (ll)(a); i -= (c))
#define overload4(a, b, c, d, e, ...) e
#define rep(...) overload4(__VA_ARGS__, rep4, rep3, rep2, rep1)(__VA_ARGS__)
#define rrep(...) overload4(__VA_ARGS__, rrep4, rrep3, rrep2, rrep1)(__VA_ARGS__)

#define all(x) (x).begin(),(x).end()
#define len(x) (ll)(x.size())
#define elif else if
#define bit(x, i) (((x)>>(i))&1)

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second

#define stoi stoll
#define abs llabs

#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define LB(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define UB(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define UNIQUE(x) \
  sort(all(x)), x.erase(unique(all(x)), x.end()), x.shrink_to_fit()

ll popcnt(ll x) { return __builtin_popcountll(x); }
ll popcnt(u64 x) { return __builtin_popcountll(x); }
ll popcnt_mod_2(ll x) { return __builtin_parityll(x); }
ll popcnt_mod_2(u64 x) { return __builtin_parityll(x); }
ll topbit(ll x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
ll topbit(u64 x) { return (x == 0 ? -1 : 63 - __builtin_clzll(x)); }
ll lowbit(ll x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }
ll lowbit(u64 x) { return (x == 0 ? -1 : __builtin_ctzll(x)); }

template <typename T>
T floor(T a, T b) {
  return a / b - (a % b && (a ^ b) < 0);
}
template <typename T>
T ceil(T x, T y) {
  return floor(x + y - 1, y);
}
template <typename T>
T bmod(T x, T y) {
  return x - y * floor(x, y);
}
template <typename T>
pair<T, T> divmod(T x, T y) {
  T q = floor(x, y);
  return {q, x - q * y};
}

template<typename T> T SUM(const vector<T> &A) {
  T s = 0; for (auto &&a: A) s += a;
  return s;
}

template <typename T>
T POP(queue<T> &que) {
  T a = que.front();
  que.pop();
  return a;
}
template <typename T>
T POP(deque<T> &que) {
  T a = que.front();
  que.pop_front();
  return a;
}
template <typename T>
T POP(pq<T> &que) {
  T a = que.top();
  que.pop();
  return a;
}
template <typename T>
T POP(pqg<T> &que) {
  T a = que.top();
  que.pop();
  return a;
}
template <typename T>
T POP(vc<T> &que) {
  T a = que.back();
  que.pop_back();
  return a;
}

template <typename F>
ll binary_search(F check, ll ok, ll ng, bool check_ok = true) {
  if (check_ok) assert(check(ok));
  while (abs(ok - ng) > 1) {
    auto x = (ng + ok) / 2;
    (check(x) ? ok : ng) = x;
  }
  return ok;
}
template <typename F>
f128 binary_search_real(F check, f128 ok, f128 ng, ll iter = 100) {
  rep(iter) {
    f128 x = (ok + ng) / 2;
    (check(x) ? ok : ng) = x;
  }
  return (ok + ng) / 2;
}

// ? は -1
vc<int> s_to_vi(const string &S, char first_char) {
  vc<int> A(S.size());
  rep(i, S.size()) { A[i] = (S[i] != '?' ? S[i] - first_char : -1); }
  return A;
}

template <typename T, typename U>
vc<T> cumsum(vc<U> &A, ll off = 1) {
  ll N = A.size();
  vc<T> B(N + 1);
  rep(i, N) { B[i + 1] = B[i] + A[i]; }
  if (off == 0) B.erase(B.begin());
  return B;
}

// stable sort
template <typename T>
vi argsort(const vector<T> &A) {
  vi ids(len(A));
  iota(all(ids), 0);
  sort(all(ids),
       [&](ll i, ll j) { return (A[i] == A[j] ? i < j : A[i] < A[j]); });
  return ids;
}

// A[I[0]], A[I[1]], ...
template <typename T>
vc<T> rearrange(const vc<T> &A, const vi &I) {
  vc<T> B(len(I));
  rep(i, len(I)) B[i] = A[I[i]];
  return B;
}

template<typename T> inline bool chmax(T &a, T b) {return ((a<b)?(a=b,true):(false));}
template<typename T> inline bool chmin(T &a, T b) {return ((a>b)?(a=b,true):(false));}

inline void wt(const char c) { cout << c; }
inline void wt(const string s) { cout << s; }
inline void wt(const char *s) { cout << s; }

template <typename T>
void wt_integer(T x) {
  if (x < 0) { cout << (i64)(x); }
  else { cout << (u64)(x); }
}
template <typename T>
void wt_real(T x) {
  cout << fixed << setprecision(15) << (long double)(x);
}

inline void wt(int x) { wt_integer(x); }
inline void wt(ll x) { wt_integer(x); }
inline void wt(i128 x) { wt_integer(x); }
inline void wt(u32 x) { wt_integer(x); }
inline void wt(u64 x) { wt_integer(x); }
inline void wt(u128 x) { wt_integer(x); }
inline void wt(double x) { wt_real(x); }
inline void wt(long double x) { wt_real(x); }
inline void wt(f128 x) { wt_real(x); }

template <class T, class U>
void wt(const pair<T, U> val) {
  wt(val.first); wt(' '); wt(val.second);
}
template <size_t N = 0, typename T>
void wt_tuple(const T t) {
  if constexpr (N < std::tuple_size<T>::value) {
    if constexpr (N > 0) { wt(' '); }
    const auto x = std::get<N>(t);
    wt(x);
    wt_tuple<N + 1>(t);
  }
}
template <class... T>
void wt(tuple<T...> tpl) {
  wt_tuple(tpl);
}
template <class T, size_t S>
void wt(const array<T, S> val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt(' ');
    wt(val[i]);
  }
}
template <class T>
void wt(const vector<T> val) {
  auto n = val.size();
  for (size_t i = 0; i < n; i++) {
    if (i) wt(' ');
    wt(val[i]);
  }
}

void print() { wt('\n'); }
template <class Head, class... Tail>
void print(Head &&head, Tail &&... tail) {
  wt(head);
  if (sizeof...(Tail)) wt(' ');
  print(forward<Tail>(tail)...);
}

void YES(bool t = 1) { print(t ? "YES" : "NO"); }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { print(t ? "Yes" : "No"); }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { print(t ? "yes" : "no"); }
void no(bool t = 1) { yes(!t); }
void onez(bool t = 1) { print(t ? 1 : 0); }
#define endl '\n'
#define dump(x) {cerr << #x " = " << x << '\n';}
#line 2 "/opt/library/ds/unionfind/unionfind.hpp"

struct UnionFind {
  ll n, n_comp;
  vi dat; // parent or (-size)
  UnionFind(ll n = 0) { build(n); }

  void build(ll m) {
    n = m, n_comp = m;
    dat.assign(n, -1);
  }

  void reset() { build(n); }

  ll operator[](ll x) {
    while (dat[x] >= 0) {
      ll parent = dat[dat[x]];
      if (parent < 0) { return dat[x]; }
      x = dat[x] = parent;
    }
    return x;
  }

  ll size(ll x) {
    x = (*this)[x];
    return -dat[x];
  }

  bool merge(ll x, ll y) {
    x = (*this)[x], y = (*this)[y];
    if (x == y) return false;
    if (-dat[x] < -dat[y]) swap(x, y);
    dat[x] += dat[y], dat[y] = x, n_comp--;
    return true;
  }
};
#line 3 "main.cpp"

int solve();
int main() {
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  while (!solve()) {break;}
  return 0;
}

int solve() {
  ll H, W;
  cin >> H >> W;
  vv(ll, A, H, W);
  rep(i, H) rep(j, W) cin >> A[i][j];
  ll ans = 0;
  UnionFind uf(H*W);
  auto conv = [&](ll y, ll x) -> ll {
    return y*W + x;
  };
  vv(bool, visited, H, W, false);
  map<ll, vc<pi>> PP;
  map<ll, map<ll,ll>> PC;
  static vi dy{-1, 1, 0, 0};
  static vi dx{ 0, 0,-1, 1};
  rep(i, H) rep(j, W) {
    if (visited[i][j]) continue;
    ll c = A[i][j];
    ll rt = conv(i, j);
    queue<pi> Q;
    Q.emplace(mp(i, j));
    visited[i][j] = true;
    while (!Q.empty()) {
      auto [y, x] = POP(Q);
      rep(k, len(dy)) {
        ll ny = y + dy[k];
        ll nx = x + dx[k];
        if ((0 <= ny) and (ny < H) and (0 <= nx) and (nx < W)) {
          if (visited[ny][nx]) continue;
          if (A[ny][nx] != c) continue;
          visited[ny][nx] = true;
          uf.merge(rt, conv(ny,nx));
          if (!PP.count(uf[rt])) PP[uf[rt]].eb(mp(i, j));
          PP[uf[rt]].eb(mp(ny, nx));
          Q.emplace(mp(ny, nx));
        }
      }
    }
    if (!PP.count(uf[rt])) PP[uf[rt]].eb(mp(i, j));
    chmax(ans, len(PP[uf[rt]]));
  }
  for (auto [id, v]: PP) {
    ll c = A[v[0].fi][v[0].se];
    set<ll> added;
    for (auto [i, j]: v) {
      rep(kk, len(dy)) {
        ll ny = i + dy[kk];
        ll nx = j + dx[kk];
        if ((0 <= ny) and (ny < H) and (0 <= nx) and (nx < W)) {
          if (A[ny][nx] == c) continue;
          ll id2 = uf[conv(ny, nx)];
          if (added.count(id2)) continue;
          PC[id][A[ny][nx]] += len(PP[id2]);
          added.insert(id2);
        }
      }
    }
  }
  set<pi> checked;
  set<ll> checked_g;
  rep(i, H) rep(j, W) {
    ll idrt = uf[conv(i, j)];
    if (checked_g.count(idrt)) continue;
    checked_g.insert(idrt);
    ll c = A[i][j];
    rep(k, len(dy)) {
      ll ny = i + dy[k];
      ll nx = j + dx[k];
      if ((0 <= ny) and (ny < H) and (0 <= nx) and (nx < W)) {
        ll id = uf[conv(ny, nx)];
        if (c == A[ny][nx]) continue;
        if (checked.count(mp(id, c))) continue;
        checked.insert(mp(id, c));
        ll counter = len(PP[id]) + PC[id][c];
        chmax(ans, counter);
      }
    }
  }
  print(ans);
  return 0;
}
accuracy: 1
time_ms: 980
memory_kb: 194336
final_rank: 14

code_snippet: #line 1 "a.cpp"
#define PROBLEM ""
#line 2 "/home/kuhaku/home/github/algo/lib/algorithm/compress.hpp"
#include <algorithm>
#include <iterator>
#include <vector>

/**
 * @brief 座標圧縮
 *
 * @tparam T 要素の型
 */
template <class T>
struct coordinate_compression {
    coordinate_compression() = default;
    coordinate_compression(const std::vector<T> &_data) : data(_data) { build(); }

    const T &operator[](int i) const { return data[i]; }
    T &operator[](int i) { return data[i]; }

    void add(T x) { data.emplace_back(x); }

    void build() {
        std::sort(std::begin(data), std::end(data));
        data.erase(std::unique(std::begin(data), std::end(data)), std::end(data));
    }

    bool exists(T x) const {
        auto it = std::lower_bound(std::begin(data), std::end(data), x);
        return it != std::end(data) && *it == x;
    }

    int get(T x) const {
        auto it = std::lower_bound(std::begin(data), std::end(data), x);
        return std::distance(std::begin(data), it);
    }

    int size() const { return std::size(data); }

  private:
    std::vector<T> data;
};

/**
 * @brief 座標圧縮
 *
 * @tparam T 要素の型
 * @param v 配列
 * @return std::vector<T>
 */
template <class T>
std::vector<T> compress(const std::vector<T> &v) {
    coordinate_compression cps(v);
    std::vector<T> res;
    res.reserve(std::size(v));
    for (auto &&x : v) res.emplace_back(cps.get(x));
    return res;
}
#line 2 "/home/kuhaku/home/github/algo/lib/template/template.hpp"
#pragma GCC target("sse4.2,avx2,bmi2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
template <class T, class U>
constexpr bool chmax(T &a, const U &b) {
    return a < (T)b ? a = (T)b, true : false;
}
template <class T, class U>
constexpr bool chmin(T &a, const U &b) {
    return (T)b < a ? a = (T)b, true : false;
}
constexpr std::int64_t INF = 1000000000000000003;
constexpr int Inf = 1000000003;
constexpr double EPS = 1e-7;
constexpr double PI = M_PI;
#line 3 "/home/kuhaku/home/github/algo/lib/template/macro.hpp"
#define FOR(i, m, n) for (int i = (m); i < int(n); ++i)
#define FORR(i, m, n) for (int i = (m)-1; i >= int(n); --i)
#define FORL(i, m, n) for (int64_t i = (m); i < int64_t(n); ++i)
#define rep(i, n) FOR (i, 0, n)
#define repn(i, n) FOR (i, 1, n + 1)
#define repr(i, n) FORR (i, n, 0)
#define repnr(i, n) FORR (i, n + 1, 1)
#define all(s) (s).begin(), (s).end()
#line 3 "/home/kuhaku/home/github/algo/lib/template/sonic.hpp"
struct Sonic {
    Sonic() {
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout << std::fixed << std::setprecision(20);
    }

    constexpr void operator()() const {}
} sonic;
#line 5 "/home/kuhaku/home/github/algo/lib/template/atcoder.hpp"
using namespace std;
using ll = std::int64_t;
using ld = long double;
template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
    return is >> p.first >> p.second;
}
template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
    for (T &i : v) is >> i;
    return is;
}
template <class T, class U>
std::ostream &operator<<(std::ostream &os, const std::pair<T, U> &p) {
    return os << '(' << p.first << ',' << p.second << ')';
}
template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
    for (auto it = v.begin(); it != v.end(); ++it) {
        os << (it == v.begin() ? "" : " ") << *it;
    }
    return os;
}
template <class Head, class... Tail>
void co(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cout << head << '\n';
    else std::cout << head << ' ', co(std::forward<Tail>(tail)...);
}
template <class Head, class... Tail>
void ce(Head &&head, Tail &&...tail) {
    if constexpr (sizeof...(tail) == 0) std::cerr << head << '\n';
    else std::cerr << head << ' ', ce(std::forward<Tail>(tail)...);
}
template <typename T, typename... Args>
auto make_vector(T x, int arg, Args... args) {
    if constexpr (sizeof...(args) == 0) return std::vector<T>(arg, x);
    else return std::vector(arg, make_vector<T>(x, args...));
}
void Yes(bool is_correct = true) {
    std::cout << (is_correct ? "Yes" : "No") << '\n';
}
void No(bool is_not_correct = true) {
    Yes(!is_not_correct);
}
void YES(bool is_correct = true) {
    std::cout << (is_correct ? "YES" : "NO") << '\n';
}
void NO(bool is_not_correct = true) {
    YES(!is_not_correct);
}
void Takahashi(bool is_correct = true) {
    std::cout << (is_correct ? "Takahashi" : "Aoki") << '\n';
}
void Aoki(bool is_not_correct = true) {
    Takahashi(!is_not_correct);
}
#line 3 "/home/kuhaku/home/github/algo/lib/tree/union_find.hpp"

/**
 * @brief 素集合データ構造
 * @details Implement (union by size) + (path compression)
 * @see https://github.com/atcoder/ac-library/blob/master/atcoder/dsu.hpp
 */
struct union_find {
    union_find() = default;
    explicit union_find(int _n) : data(_n, -1) {}

    int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
    int get_root(int x) { return root(x); }

    bool is_root(int x) const { return data[x] < 0; }

    bool same(int x, int y) { return root(x) == root(y); }
    bool is_same(int x, int y) { return same(x, y); }

    int size(int x) { return -(data[root(x)]); }
    int get_size(int x) { return size(x); }

    std::vector<int> leaders() {
        std::vector<int> res;
        for (int i = 0; i < (int)data.size(); ++i) {
            if (is_root(i)) res.emplace_back(i);
        }
        return res;
    }

    bool unite(int x, int y) {
        x = root(x), y = root(y);
        if (x == y) return false;
        if (data[x] > data[y]) std::swap(x, y);
        data[x] += data[y];
        data[y] = x;
        return true;
    }

    template <class F>
    bool unite(int x, int y, F f) {
        x = root(x), y = root(y);
        if (x != y) {
            if (data[x] > data[y]) std::swap(x, y);
            data[x] += data[y];
            data[y] = x;
        }
        f(x, y);
        return x != y;
    }

  private:
    std::vector<int> data;
};
#line 5 "a.cpp"

int main(void) {
    int h, w;
    cin >> h >> w;
    vector a(h, vector(w, 0));
    cin >> a;

    auto in_field = [&](int x, int y) {
        return 0 <= x && x < h && 0 <= y && y < w;
    };

    union_find uf(h * w);
    vector<int> dx = {1, 0}, dy = {0, 1};
    rep (x, h) {
        rep (y, w) {
            rep (k, 2) {
                int nx = x + dx[k], ny = y + dy[k];
                if (!in_field(nx, ny))
                    continue;
                if (a[x][y] == a[nx][ny])
                    uf.unite(x * w + y, nx * w + ny);
            }
        }
    }

    auto ls = uf.leaders();
    vector<int> cs(ls.size()), ss(ls.size());
    rep (i, ls.size()) {
        int x = ls[i] / w;
        int y = ls[i] % w;
        cs[i] = a[x][y];
        ss[i] = uf.size(ls[i]);
    }
    coordinate_compression cps(ls);
    vector<set<int>> v(ls.size());
    rep (x, h) {
        rep (y, w) {
            rep (k, 2) {
                int nx = x + dx[k], ny = y + dy[k];
                if (!in_field(nx, ny))
                    continue;
                if (a[x][y] != a[nx][ny]) {
                    int l = cps.get(uf.root(x * w + y));
                    int r = cps.get(uf.root(nx * w + ny));
                    v[l].emplace(r);
                    v[r].emplace(l);
                }
            }
        }
    }

    vector<unordered_map<int, int>> mp(ls.size());
    rep (i, ls.size()) {
        for (int e : v[i]) {
            mp[i][cs[e]] += ss[e];
        }
    }

    int ans = *max_element(all(ss));
    rep (i, ls.size()) {
        for (auto [x, y] : mp[i]) {
            chmax(ans, ss[i] + y);
        }
    }
    co(ans);

    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 127948
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
#define all(A) A.begin(),A.end()
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;

vll dx = { -1,0,1,0 };
vll dy = { 0,1,0,-1 };
int main() {
    ll H, W;
    cin >> H >> W;
    vvll A(H, vll(W));
    rep(h, H)rep(w, W)cin >> A[h][w];
    vvll B(H, vll(W, -1));
    ll c = 0;
    vll CN;
    vll CL;
    rep(h, H)rep(w, W) {
        if (B[h][w] != -1)continue;
        queue<pair<ll, ll>> Q;
        Q.push({ h,w });
        ll cnt = 0;
        while (!Q.empty()) {
            ll y = Q.front().first;
            ll x = Q.front().second;
            Q.pop();
            if (B[y][x] != -1)continue;
            B[y][x] = c;
            cnt++;
            rep(d, 4) {
                ll ny = y + dy[d];
                ll nx = x + dx[d];
                if (ny < 0 || nx < 0 || ny >= H || nx >= W)continue;
                if (B[ny][nx] != -1)continue;
                if (A[ny][nx] != A[y][x])continue;
                Q.push({ ny,nx });
            }
        }
        c++;
        CN.push_back(cnt);
        CL.push_back(A[h][w]);
    }
    vector<set<ll>> S(c);
    rep(h, H)rep(w, W - 1) {
        if (B[h][w] != B[h][w + 1]) {
            S[B[h][w]].insert(B[h][w + 1]);
            S[B[h][w + 1]].insert(B[h][w]);
        }
    }
    rep(h, H - 1)rep(w, W) {
        if (B[h][w] != B[h + 1][w]) {
            S[B[h][w]].insert(B[h + 1][w]);
            S[B[h + 1][w]].insert(B[h][w]);
        }
    }
    ll an = 0;
    rep(i, c) {
        map<ll, ll> cl;
        ll res = 0;
        for (auto s : S[i]) {
            cl[CL[s]] += CN[s];
            res = max(res, cl[CL[s]]);
        }
        an = max(an, res + CN[i]);
    }
    cout << an << endl;
}
accuracy: 1
time_ms: 170
memory_kb: 69564
final_rank: 11

code_snippet: /* -*- coding: utf-8 -*-
 *
 * 0749.cc: 塗りつぶし (Painting)
 */

#include<cstdio>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#include<utility>
 
using namespace std;

/* constant */

const int MAX_H = 500;
const int MAX_W = 500;
const int MAX_N = MAX_H * MAX_W;
const int dxs[] = { 1, 0, -1, 0 }, dys[] = { 0, -1, 0, 1 };

/* typedef */

typedef set<int> si;
typedef pair<int,int> pii;
typedef queue<pii> qpii;
typedef map<int,int> mii;

/* global variables */

int as[MAX_H][MAX_W], gs[MAX_H][MAX_W];
int gas[MAX_N], gcs[MAX_N];
si nbrs[MAX_N];

/* subroutines */

/* main */

int main() {
  int h, w;
  scanf("%d%d", &h, &w);
  for (int i = 0; i < h; i++)
    for (int j = 0; j < w; j++) scanf("%d", as[i] + j);

  for (int i = 0; i < h; i++) fill(gs[i], gs[i] + w, -1);

  int gn = 0;
  
  for (int y = 0; y < h; y++)
    for (int x = 0; x < w; x++)
      if (gs[y][x] < 0) {
	int g = gs[y][x] = gn++;
	int a = gas[g] = as[y][x];
	gcs[g]++;

	qpii q;
	q.push(pii(y, x));

	while (! q.empty()) {
	  auto u = q.front(); q.pop();
	  int uy = u.first, ux = u.second;

	  for (int di = 0; di < 4; di++) {
	    int vy = uy + dys[di], vx = ux + dxs[di];
	    if (vy >= 0 && vy < h && vx >= 0 && vx < w &&
		gs[vy][vx] < 0 && as[vy][vx] == a) {
	      gs[vy][vx] = g;
	      gcs[g]++;
	      q.push(pii(vy, vx));
	    }
	  }
	}
      }

  for (int y = 0; y < h; y++)
    for (int x = 0; x < w; x++) {
      int g0 = gs[y][x], g1;
      if (y + 1 < h && (g1 = gs[y + 1][x]) != g0) {
	nbrs[g0].insert(g1);
	nbrs[g1].insert(g0);
      }
      if (x + 1 < w && (g1 = gs[y][x + 1]) != g0) {
	nbrs[g0].insert(g1);
	nbrs[g1].insert(g0);
      }
    }

  int maxs = 0;
  for (int i = 0; i < gn; i++) {
    mii acs;
    for (auto v: nbrs[i]) acs[gas[v]] += gcs[v];
    int maxc = 0;
    for (auto ac: acs) maxc = max(maxc, ac.second);
    maxs = max(maxs, gcs[i] + maxc);
  }

  printf("%d\n", maxs);

  return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 65416
final_rank: 9

code_snippet: #include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <algorithm>
#include <sstream>
#include <tuple>
#include <unordered_map>
#include <queue>
#include <complex>
#include <iomanip>
#include <set>
#include <unordered_set>
using namespace std;
typedef long long ll;

int r, c;
int tmp = 0;
const int S = 250001;

int* cellcolor;
int* visited;
vector<int> groups;
int* number_cell_group;
vector<int> nexts[S];

void dfs(int a, int prev, int g)
{
    if (cellcolor[a] != prev)
    {
        nexts[g].emplace_back(a);
        return;
    }
    if (visited[a] != -1)
        return;

    int col = cellcolor[a];
    visited[a] = g;
    tmp++;
    int y = a / c;
    int x = a % c;
    if (x + 1 < c)
        dfs(a + 1, col, g);
    if (x - 1 >= 0)
        dfs(a - 1, col, g);
    if (y + 1 < r)
        dfs(a + c, col, g);
    if (0 <= y - 1)
        dfs(a - c, col, g);
}

int main(void)
{
    ifstream input;
    input.open("input.txt");
    std::ifstream in;
    if (input)
    {
        input.close();
        in = std::ifstream("input.txt");
        std::cin.rdbuf(in.rdbuf());
    }
    cin >> r >> c;
    int N = r * c;

    cellcolor = new int[N];
    visited = new int[N];
    number_cell_group = new int[N];

    for (int i = 0; i < N; i++)
    {
        cin >> cellcolor[i];
        visited[i] = -1;
        number_cell_group[i] = -1;
    }

    for (int i = 0; i < N; i++)
    {
        tmp = 0;
        if (visited[i] != -1)
            continue;
        dfs(i, cellcolor[i], i);
        number_cell_group[i] = tmp;
        groups.emplace_back(i);
    }

    int maximum = 0;
    for (auto g : groups)
    {
        unordered_set<int> gnext;
        for (auto ne : nexts[g])
            gnext.insert(visited[ne]);
        maximum = max(number_cell_group[g], maximum);
        unordered_map<int, int> nextmap;
        for (auto ng : gnext)
            nextmap[cellcolor[ng]] += number_cell_group[ng];

        for (auto z : nextmap)
        {
            auto temp = z.second + number_cell_group[g];
            maximum = max(temp, maximum);
        }
    }
    cout << maximum << endl;
}
accuracy: 1
time_ms: 160
memory_kb: 36568
final_rank: 7

code_snippet: #define rep(i,n) for(int i=0;i<(int)(n);i++)
#define ALL(v) v.begin(),v.end()
typedef long long ll;
 
#include<bits/stdc++.h>
using namespace std;

class Dis{
  public:
  vector<ll> rank,p,siz;
  
  Dis(int s){
    rank.resize(s,0);
    p.resize(s,0);
    siz.resize(s,1);
    rep(i,s) makeSet(i);
  }
  
  void makeSet(int x){
    p[x]=x;
    rank[x]=0;
  }
  
  bool same(int x,int y){
    return root(x)==root(y);
  }
  
  void unite(int x,int y){
    if(same(x,y)) return;
    link(root(x),root(y));
  }
  
  void link(int x,int y){
    if(rank[x]>rank[y]){
      p[y]=x;
      siz[x]+=siz[y];
    }
    else{
      p[x]=y;
      siz[y]+=siz[x];
      if(rank[x]==rank[y]) rank[y]++;
    }
  }
  
  int root(int x){
    if(x != p[x]) p[x]=root(p[x]);
    return p[x];
  }
  
  int size(int x){
    return siz[root(x)];
  }
};

int A[510][510];
set<int> G[252525];
 
int main(){
  ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  
  int h,w;
  cin>>h>>w;
  rep(i,h) rep(j,w) cin>>A[i][j];
  Dis ds=Dis(h*w);
  
  rep(i,h) rep(j,w){
    if(i<h-1 && A[i][j]==A[i+1][j]) ds.unite(i*w+j,(i+1)*w+j);
    if(j<w-1 && A[i][j]==A[i][j+1]) ds.unite(i*w+j,i*w+j+1);
  }
  
  rep(i,h) rep(j,w){
    if(i<h-1 && ds.root(i*w+j)!=ds.root((i+1)*w+j)){
      G[ds.root(i*w+j)].insert(ds.root((i+1)*w+j));
      G[ds.root((i+1)*w+j)].insert(ds.root(i*w+j));
    }
    if(j<w-1 && ds.root(i*w+j)!=ds.root(i*w+j+1)){
      G[ds.root(i*w+j)].insert(ds.root(i*w+j+1));
      G[ds.root(i*w+j+1)].insert(ds.root(i*w+j));
    }
  }
  
  int ans=0;
  rep(i,h) rep(j,w){
    if(ds.root(i*w+j)!=i*w+j) continue;
    map<int,int> m;
    for(auto nv:G[ds.root(i*w+j)]){
      int ni=nv/w,nj=nv%w;
      m[A[ni][nj]]+=ds.size(nv);
    }
    int tmp=0;
    for(auto [a,b]:m) tmp=max(tmp,b);
    ans=max(ans,tmp+ds.size(i*w+j));
  }
  cout<<ans<<endl;
  
  return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 68480
final_rank: 10

code_snippet: #include <algorithm>
#include <cassert>
#include <vector>

namespace atcoder {

// Implement (union by size) + (path compression)
// Reference:
// Zvi Galil and Giuseppe F. Italiano,
// Data structures and algorithms for disjoint set union problems
struct dsu {
  public:
    dsu() : _n(0) {}
    explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = leader(parent_or_size[a]);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) {
            result[i].reserve(group_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            result[leader_buf[i]].push_back(i);
        }
        result.erase(
            std::remove_if(result.begin(), result.end(),
                           [&](const std::vector<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

  private:
    int _n;
    // root node: -1 * component size
    // otherwise: parent
    std::vector<int> parent_or_size;
};

}  // namespace atcoder


#include <bits/stdc++.h>
// <atcoder/dsu>
using namespace std;

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

int main() {
  int h, w;
  cin >> h >> w;
  vector<vector<int>> a(h, vector<int>(w));
  for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) cin >> a[i][j];
  atcoder::dsu uf(h * w);
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      for (int k = 0; k < 4; k++) {
        int x = i + dx[k], y = j + dy[k];
        if (0 <= x and x < h and 0 <= y and y < w and a[i][j] == a[x][y])
          uf.merge(i * w + j, x * w + y);
      }
    }
  }
  int ans = 0;
  auto g = uf.groups();
  map<int, int> l;
  for (auto s: g) l[uf.leader(s[0])] = s.size();
  for (auto s: g) {
    map<int, set<int>> m;
    for (auto p: s){
      int i = p / w, j = p % w;
      for (int k = 0; k < 4; k++){
        int x = i + dx[k], y = j + dy[k];
        if (0 <= x and x < h and 0 <= y and y < w and a[i][j] != a[x][y])
          m[a[x][y]].insert(uf.leader(x * w + y));
      }
    }
    map<int, int> m2;
    for (auto p: m) for (int i: p.second) m2[p.first] += uf.size(i);
    int d = 0;
    for (auto p: m2) d = max(d, p.second);
    ans = max(ans, (int)s.size() + d);
  }
  cout << ans << '\n';
}
accuracy: 1
time_ms: 220
memory_kb: 44848
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001




#define SIZE 505*505

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];

int H,W;
int A[505][505];
int d_row[4] = {-1,0,0,1},d_col[4] = {0,-1,1,0};
int value[SIZE];
vector<int> V[SIZE];

bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}

int getIndex(int row,int col){

	return row*W + col;
}

int main(){

	scanf("%d %d",&H,&W);

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			scanf("%d",&A[row][col]);
		}
	}

	N = H*W;

	for(int i = 0; i < N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			int from = getIndex(row,col);

			for(int i = 0; i < 4; i++){

				int adj_row = row+d_row[i];
				int adj_col = col+d_col[i];
				if(!rangeCheck(adj_row,adj_col)||A[row][col] != A[adj_row][adj_col])continue;

				int to = getIndex(adj_row,adj_col);

				unite(from,to);
			}
		}
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			int from = getIndex(row,col);

			for(int i = 0; i < 4; i++){

				int adj_row = row+d_row[i];
				int adj_col = col+d_col[i];
				if(!rangeCheck(adj_row,adj_col))continue;

				int to = getIndex(adj_row,adj_col);

				//辺で接するグループの組合せを記録しておく
				if(A[row][col] != A[adj_row][adj_col]){

					V[get_boss(from)].push_back(get_boss(to));
				}
			}
		}
	}

	int ans = 0;

	vector<int> vec;

	for(int i = 0; i < N; i++){
		if(i != get_boss(i))continue;

		vec.push_back(i);

		chmax(ans,num_member[i]);
		int tmp_row = i/W;
		int tmp_col = i%W;
		value[i] = A[tmp_row][tmp_col]; //そのグループの数字

		if(V[i].size() == 0)continue;

		sort(V[i].begin(),V[i].end());
		V[i].erase(unique(V[i].begin(),V[i].end()),V[i].end());
	}

	for(int i = 0; i < vec.size(); i++){

		//隣接するグループの数字ごとに、総和を集計する
		map<int,int> MAP;
		for(int k = 0; k < V[vec[i]].size(); k++){

			MAP[value[V[vec[i]][k]]] += num_member[V[vec[i]][k]];
		}

		for(auto at = MAP.begin(); at != MAP.end(); at++){

			int work = num_member[vec[i]] + at->second;
			chmax(ans,work);
		}
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 25080
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
#define EPS 0.000000001




#define SIZE 505*505

int N;
int boss[SIZE],height[SIZE],num_member[SIZE];

int H,W;
int A[505][505];
int d_row[4] = {-1,0,0,1},d_col[4] = {0,-1,1,0};
int value[SIZE];
vector<int> V[SIZE];

bool rangeCheck(int row,int col){

	return row >= 0 && row <= H-1 && col >= 0 && col <= W-1;
}


int get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int isSame(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[boss_x] > height[boss_y]){

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;

	}else if(height[boss_x] < height[boss_y]){

		num_member[boss_y] += num_member[boss_x];
		boss[boss_x] = boss_y;

	}else{ //height[boss_x] == height[boss_y]

		num_member[boss_x] += num_member[boss_y];
		boss[boss_y] = boss_x;
		height[x]++;
	}
}

int getIndex(int row,int col){

	return row*W + col;
}

int main(){

	scanf("%d %d",&H,&W);

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			scanf("%d",&A[row][col]);
		}
	}

	N = H*W;

	for(int i = 0; i < N; i++){

		boss[i] = i;
		height[i] = 0;
		num_member[i] = 1;
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			int from = getIndex(row,col);

			for(int i = 0; i < 4; i++){

				int adj_row = row+d_row[i];
				int adj_col = col+d_col[i];
				if(!rangeCheck(adj_row,adj_col)||A[row][col] != A[adj_row][adj_col])continue;

				int to = getIndex(adj_row,adj_col);

				unite(from,to);
			}
		}
	}

	for(int row = 0; row < H; row++){
		for(int col = 0; col < W; col++){

			int from = getIndex(row,col);

			for(int i = 0; i < 4; i++){

				int adj_row = row+d_row[i];
				int adj_col = col+d_col[i];
				if(!rangeCheck(adj_row,adj_col))continue;

				int to = getIndex(adj_row,adj_col);

				//辺で接するグループの組合せを記録しておく
				if(A[row][col] != A[adj_row][adj_col]){

					V[get_boss(from)].push_back(get_boss(to));
				}
			}
		}
	}

	int ans = 0;

	vector<int> vec;

	for(int i = 0; i < N; i++){
		if(i != get_boss(i))continue;

		vec.push_back(i);

		//printf("num_member[%d]:%d\n",i,num_member[i]);

		chmax(ans,num_member[i]);
		int tmp_row = i/W;
		int tmp_col = i%W;
		value[i] = A[tmp_row][tmp_col]; //そのグループの数字

		if(V[i].size() == 0)continue;

		sort(V[i].begin(),V[i].end());
		V[i].erase(unique(V[i].begin(),V[i].end()),V[i].end());
	}

	for(int i = 0; i < vec.size(); i++){

		//隣接するグループの数字ごとに、総和を集計する
		map<int,int> MAP;
		for(int k = 0; k < V[vec[i]].size(); k++){

			MAP[value[V[vec[i]][k]]] += num_member[V[vec[i]][k]];
		}

		for(auto at = MAP.begin(); at != MAP.end(); at++){

			int work = num_member[vec[i]] + at->second;
			chmax(ans,work);
		}
	}

	printf("%d\n",ans);

	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 25132
final_rank: 3

code_snippet: #include <bits/extc++.h>

using namespace std;

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,n) for(int i=1;i<=(n);++i)
#define all(x) begin(x),end(x)
#define Fixed fixed << setprecision(12)
#define updiv(a, b) (((a) + (b) - 1) / (b))
using pii = pair<int,int>;
constexpr int32_t INF  = 0x3f3f3f3f;
constexpr int_fast64_t LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1e9+7;
constexpr int mod2 = 998244353;

template <class Func>
class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}

    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template<class T, class U> istream& operator>>(istream& is, pair<T, U>& p){ is >> p.first >> p.second; return (is); }
template<class T, class U> ostream& operator<<(ostream& os, pair<T, U>& p){ os << p.first << ' ' << p.second; return (os); }
template<class T> istream& operator>>(istream& is, vector<T>& v){ for (auto &&e : v) is >> e; return (is); }
template<class T> ostream& operator<<(ostream& os, vector<T>& v){ for (auto &&e : v) os << e << ' '; return (os); }

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using max_heap = priority_queue<T>;
template <class T> using min_heap = priority_queue<T, vector<T>, greater<T> >;
template <class A, class B> using umap = unordered_map<A, B>;
template <class T> using uset = unordered_set<T>;

template <class T> using Max_Heap = __gnu_pbds::priority_queue<T, less<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Min_Heap = __gnu_pbds::priority_queue<T, greater<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Set = __gnu_pbds::tree<T, __gnu_pbds::null_type, less<T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
template <class K, class V> using Umap = __gnu_pbds::gp_hash_table<K, V>;
template <class T> using Rope = __gnu_cxx::rope<T>;
using Trie = __gnu_pbds::trie<string, __gnu_pbds::null_type, __gnu_pbds::trie_string_access_traits<>, __gnu_pbds::pat_trie_tag, __gnu_pbds::trie_prefix_search_node_update>;

template <class T> void bye(T x){ cout << x << '\n'; exit(0); }
inline int square(int a){ return (a * a); }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1};
constexpr int dy[] = {0,-1,0,1,1,-1,-1,1};

struct UnionFind{
    int n;
    vector<int> data;

    UnionFind(int sz) : n(sz), data(sz, -1){}

    bool unite(int x, int y){
        x = find(x), y = find(y);
        if(x == y) return (false);
        if(data[x] > data[y]) swap(x, y);
        data[x] += data[y];
        data[y] = x;
        return (true);
    }

    int find(int k){
        if(data[k] < 0) return (k);
        return (data[k] = find(data[k]));
    }

    int size(int k){
        return (-data[find(k)]);
    }

    bool same(int x, int y){
        return (find(x) == find(y));
    }

    vector<vector<int> > groups(){
        vector<int> leader_buf(n), group_size(n);
        for(int i = 0; i < n; ++i){
            leader_buf[i] = find(i);
            group_size[leader_buf[i]]++;
        }
        vector<vector<int> > res(n);
        for(int i = 0; i < n; ++i){
            res[i].reserve(group_size[i]);
        }
        for(int i = 0; i < n; ++i){
            res[leader_buf[i]].emplace_back(i);
        }
        res.erase(
            remove_if(res.begin(), res.end(),
                      [&](const vector<int>& v){ return (v.empty()); }),
            res.end());
        return (res);
    }
};

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout.setf(ios_base::fixed);
    cout.precision(12);

    int h, w;
    cin >> h >> w;

    assert(1 <= h && h <= 500);
    assert(1 <= w && w <= 500);

    vector<vector<int> > a(h, vector<int>(w));

    cin >> a;

    for (auto v : a) for (auto e : v) assert(1 <= e && e <= 1000000000);

    vector<int> c;

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            c.push_back(a[i][j]);
        }
    }

    sort(all(c));
    c.erase(unique(all(c)), c.end());

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            a[i][j] = lower_bound(all(c), a[i][j]) - c.begin();
        }
    }

    auto inside = [&](int y, int x) {
        return (0 <= y && y < h && 0 <= x && x < w);
    };

    int res = 0;

    UnionFind uf(h * w);

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            for (int k = 0; k < 4; ++k) {
                int ty = i + dy[k];
                int tx = j + dx[k];
                if (inside(ty, tx) && a[i][j] == a[ty][tx]) {
                    uf.unite(i * w + j, ty * w + tx);
                }
            }
        }
    }

    vector<vector<int> > g(h * w);

    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            for (int k = 0; k < 4; ++k) {
                int ty = i + dy[k];
                int tx = j + dx[k];
                int cur = i * w + j;
                int tar = ty * w + tx;
                if (inside(ty, tx) && !uf.same(cur, tar)) {
                    g[uf.find(cur)].push_back(uf.find(tar));
                }
            }
        }
    }

    vector<umap<int, int> > cnt(h * w);

    for (int i = 0; i < h * w; ++i) {
        chmax(res, uf.size(i));
        sort(all(g[i]));
        g[i].erase(unique(all(g[i])), g[i].end());
        for (auto tar : g[i]) {
            cnt[i][a[tar / w][tar % w]] += uf.size(tar);
        }
        for (auto [c, s] : cnt[i]) {
            chmax(res, s + uf.size(i));
        }
    }

    cout << res << '\n';

    return (0);
}
accuracy: 1
time_ms: 160
memory_kb: 80116
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct dsu {
    public:
    int csz;
    dsu() : _n(0) {}
    dsu(int n) : _n(n), csz(n), parent_or_size(n, -1) {}

    int merge(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        int x = leader(a), y = leader(b);
        if (x == y) return x;
        if (-parent_or_size[x] < -parent_or_size[y]) std::swap(x, y);
        csz--;
        parent_or_size[x] += parent_or_size[y];
        parent_or_size[y] = x;
        return x;
    }

    bool same(int a, int b) {
        assert(0 <= a && a < _n);
        assert(0 <= b && b < _n);
        return leader(a) == leader(b);
    }

    int leader(int a) {
        assert(0 <= a && a < _n);
        if (parent_or_size[a] < 0) return a;
        return parent_or_size[a] = leader(parent_or_size[a]);
    }

    int size(int a) {
        assert(0 <= a && a < _n);
        return -parent_or_size[leader(a)];
    }

    std::vector<std::vector<int>> groups() {
        std::vector<int> leader_buf(_n), group_size(_n);
        for (int i = 0; i < _n; i++) {
            leader_buf[i] = leader(i);
            group_size[leader_buf[i]]++;
        }
        std::vector<std::vector<int>> result(_n);
        for (int i = 0; i < _n; i++) {
            result[i].reserve(group_size[i]);
        }
        for (int i = 0; i < _n; i++) {
            result[leader_buf[i]].push_back(i);
        }
        result.erase(
            std::remove_if(result.begin(), result.end(),
                           [&](const std::vector<int>& v) { return v.empty(); }),
            result.end());
        return result;
    }

    private:
    int _n;
    // root node: -1 * component size
    // otherwise: parent
    std::vector<int> parent_or_size;
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int h, w;
    cin >> h >> w;
    vector<vector<int>> A(h, vector<int>(w));
    for(int y = 0; y < h; y++){
        for(int x = 0; x < w; x++){
            cin >> A[y][x];
        }
    }

    int ans = 0;
    dsu uf(h * w);
    auto f = [&](int y, int x){return y * w + x; };
    auto g = [&](int v){return make_pair(v / w, v % w); };
    for(int y = 0; y < h; y++){
        for(int x = 0; x < w; x++){
            if(x + 1 < w && A[y][x] == A[y][x + 1])uf.merge(f(y, x), f(y, x + 1));
            if(y + 1 < h && A[y][x] == A[y + 1][x])uf.merge(f(y, x), f(y + 1, x));
        }
    }

    auto G = uf.groups();
    for(auto &&vec:G){
        set<int> S;
        map<int,int> mp;
        int v = uf.leader(vec[0]);
        S.insert(v);
        for(auto &&v:vec){
            int y, x;
            tie(y, x) = g(v);
            for(int i = 0; i < 4; i++){
                int ny = y + (i == 0) - (i == 1);
                int nx = x + (i == 2) - (i == 3);
                if(ny < 0 || nx < 0 || ny >= h || nx >= w)continue;
                if(S.count(uf.leader(f(ny, nx))))continue;
                S.insert(uf.leader(f(ny, nx)));
                mp[A[ny][nx]] += uf.size(f(ny, nx));
            }
        }
        ans = max(ans, int(vec.size()));
        for(auto &&p:mp){
            ans = max(ans, int(vec.size()) + p.second);
        }
    }
    cout << ans << '\n';
}
accuracy: 1
time_ms: 130
memory_kb: 26968
final_rank: 6