import std.stdio, std.string, std.range, std.conv, std.array, std.algorithm, std.math, std.typecons, std.functional;
import std.container;

void main() {
    auto tmp = readln.split.to!(long[]);
    auto N = tmp[0], K = tmp[1];

    alias Sushi = Tuple!(long, "t", long, "d");
    Sushi[] sushiList;
    foreach (i; 0..N) {
        tmp = readln.split.to!(long[]);
        sushiList ~= Sushi(tmp[0], tmp[1]);
    }
    sushiList = sushiList.sort!((a,b) => a.d < b.d).array;

    const totalNetaNum = sushiList
        .dup
        .sort!((a,b) => a.t < b.t)
        .group!((a,b) => a.t == b.t)
        .count;

    auto tree = redBlackTree!(true, Sushi)([]);
    foreach (s; sushiList.retro.take(K)) {
        tree.insert(s);
    }

    int[] currentNetaList = new int[N+1];
    foreach (s; tree) {
        currentNetaList[s.t]++;
    }

    auto currentNetaNum = currentNetaList.count!(i => i > 0);

    auto maxScore = tree[].map!(s => s.d).sum + currentNetaNum^^2;

    while (currentNetaNum < min(K,totalNetaNum)) {
        auto removeTarget =
            sushiList
            .filter!(s => currentNetaList[s.t] > 1)
            .front;

        tree.removeKey(removeTarget);
        currentNetaList[removeTarget.t]--;

        auto addTarget =
            sushiList
            .retro
            .filter!(s => currentNetaList[s.t] == 0)
            .front;

        tree.insert(addTarget);
        currentNetaList[addTarget.t]++;

        currentNetaNum++;

        maxScore = max(maxScore, tree[].map!(s => s.d).sum + currentNetaNum^^2);
    }
    writeln(maxScore);
}

