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;

    bool[100_001] totalNetaList;
    long totalNetaNum = 0;
    foreach (s; sushiList) {
        if (totalNetaList[s.t]) continue;
        totalNetaList[s.t] = true;
        totalNetaNum++;
    }

    auto left = redBlackTree!("a > b", true, Sushi)(sushiList);
    auto tree = redBlackTree!("a < b", true, Sushi)([]);

    long[100_001] currentNetaList;
    long currentDelicious = 0;
    long currentNetaNum = 0;
    foreach (s; sushiList.retro.take(K)) {
        if (currentNetaList[s.t]++ == 0) currentNetaNum++;
        currentDelicious += s.d;
        left.removeKey(s);
        tree.insert(s);
    }

    auto maxScore = currentDelicious + currentNetaNum^^2;

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

        currentDelicious -= removeTarget.d;
        currentNetaList[removeTarget.t]--;
        tree.removeKey(removeTarget);
        left.insert(removeTarget);

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

        currentDelicious += addTarget.d;
        currentNetaList[addTarget.t]++;
        left.removeKey(addTarget);
        tree.insert(addTarget);

        currentNetaNum++;

        maxScore = max(maxScore, currentDelicious + currentNetaNum^^2);
    }
    writeln(maxScore);
}

