#include <algorithm>
#include <cstring>
#include <iostream>
#include <fstream>
#include <vector>

int main(int argc,char *argv[])
{
    char buffer[0x10000]; // extent if needed or make it dynamic if you like

    std::ifstream in("list.txt", std::ios::binary);
    std::ofstream out("nodup.txt", std::ios::binary);

    //std::cin.rdbuf(in.rdbuf());
    //std::cout.rdbuf(out.rdbuf());

    std::ios_base::sync_with_stdio(false); // this makes an actual difference!

    std::vector<size_t>      I; I.reserve(0x100);   // field indices to sort
    std::vector<char const*> P; P.reserve(0x100);   // field pointers
    // bools to mark duplicated fields (i don't like vector<bool>)
    std::vector<char>        F; F.reserve(0x100);

    while (in.getline(buffer,sizeof(buffer)))
    {
        // setup index and pointer array for all fields
        I.clear();
        P.clear();
        size_t n = 0;
        I.push_back(n);
        P.push_back(buffer);
        ++n;
        {
            auto p = buffer;
            while (*p != '\0')
            {
                if (*p == ';')
                {
                    *p = '\0'; ++p;
                    I.push_back(n); P.push_back(p); ++n;
                }
                else ++p;
            }
        }
        { // sort fields
            struct Compare
            {
                Compare(std::vector<char const*> const &P) : P(&P) {}
                bool operator()(size_t lhs,size_t rhs) const
                {
                    return strcmp((*P)[lhs],(*P)[rhs]) < 0;
                }
                std::vector<char const*> const *P;
            };
            std::stable_sort(&I[3],&I[I.size()],Compare(P));
        }
        { // mark duplicates
            F.clear(); F.resize(n);
            size_t i=3,j=4;
            while (j < n)
            {
                if (0 == strcmp(P[I[i]],P[I[j]]))
                {
                    F[I[j]] = 1;
                    ++j;
                }
                else
                {
                    i = j; ++j;
                }
            }
        }
        // print result
        for (size_t i=0; i<n-1; ++i)
        {
            if (!F[i])
                out << P[i];
            out << ';';
        }
        if (!F[n-1])
            out << P[n-1];
        out << '\n';
    }
    if (!in.eof())
    {
        std::cerr << "line probably too long (please extend buffer size)\n";
        exit(1);
    }

    return 0;
}
