How can I optimize this mergesort?
First you should define your ordering separately from your merge:

bool operator&lt;(people const&amp; lhs, people const&amp; rhs)
{
    if (lhs.lname &lt; rhs.lname)  {return true;}
    if (lhs.lname &gt; rhs.lname)  {return false;}

    // lhs.lname == rhs.lname 
    if (lhs.fname &lt; rhs.fname)  {return true;}
    if (lhs.fname &gt; rhs.fname)  {return false;}

    // lhs.lname == rhs.lname  &amp;&amp; lhs.fname == rhs.fname
    if (lhs.dob &lt; rhs.dob)      {return true;}

    // Optimize away the last test.
    //if (lhs.dob &gt; rhs.dob)      {return false;}

    return false;
}


Incrementing by one can be done with the operator++

j += 1;
// Easier to write as:
++j;


Or you can do it in-place with:

temp[k] = arr[i];
i += 1;
// Easier to write as
temp[k] = arr[i++];


Using new/delete is a bad idea. It makes you do all the memory management. It is better to use classes that do it all for you. In your case std::vector is a better choice for memory management of arrays

people * temp = new people[end2];
....
delete [] temp;
// Better to use std::vector
std::vector&lt;people&gt;  temp(end2);
....


Prefer to use standard algorithms rather than manual loops.

  for(int c = 0; c &lt; end2; c += 1) {
    arr[c] = temp[c];
  }
  // Use std::copy
  std::copy(temp.begin(), temp.end(), arr);


If you are copying something and not going to use the original again. Then try and move the object to the destination rather than copying it.

  temp[k] = arr[i];
  // Prefer to move rather than copy
  // if you are not going to use the value at arr[i] again.
  temp[k] = std::move(arr[i]);

  // Note this assumes you have defined move constructor and move assignment operator
  // for the class people. If you have not defined these operations then it will
  // default to use the normal copy versions.


Now your merge becomes more readable:

void mymerge(people  *arr, int end1, int end2)
{
  int i = 0;
  int j = end1;
  std::vector&lt;people&gt;  temp;
  temp.reserve(end2);

  while(i &lt; end1 &amp;&amp; j &lt; end2)
  {
      people&amp;  src =  (arr[i] &lt; arr[j])
                         ? arr[i++]
                         : arr[j++];
      temp.emplace_back(std::move(src));
  }

  std::move(&amp;arr[i], &amp;arr[end1], std::back_inserter(temp));
  std::move(&amp;arr[j], &amp;arr[end2], std::back_inserter(temp));

  std::move(temp.begin(), temp.end(), arr);
}


Now that I have cleaned up the mymerge() function I can understand what you are doing and it looks like it should work. But it requires the input sections to be already pre-sorted. I am not sure how your double loop in main() achieves this.