Problem:
Score : 500 points

Problem Statement

Let N be a positive integer.

There is a numerical sequence of length 3N, a = (a_1, a_2, ..., a_{3N}).
Snuke is constructing a new sequence of length 2N, a', by removing exactly N elements from a without changing the order of the remaining elements.
Here, the score of a' is defined as follows: (the sum of the elements in the first half of a') - (the sum of the elements in the second half of a').

Find the maximum possible score of a'.

Constraints

1 ≤ N ≤ 10^5

a_i is an integer.

1 ≤ a_i ≤ 10^9

Partial Score

In the test set worth 300 points, N ≤ 1000.

Input

Input is given from Standard Input in the following format:

N
a_1 a_2 ... a_{3N}

Output

Print the maximum possible score of a'.

Sample Input 1

2
3 1 4 1 5 9

Sample Output 1

1

When a_2 and a_6 are removed, a' will be (3, 4, 1, 5), which has a score of (3 + 4) - (1 + 5) = 1.

Sample Input 2

1
1 2 3

Sample Output 2

-1

For example, when a_1 are removed, a' will be (2, 3), which has a score of 2 - 3 = -1.

Sample Input 3

3
8 2 2 7 4 6 5 3 8

Sample Output 3

5

For example, when a_2, a_3 and a_9 are removed, a' will be (8, 7, 4, 6, 5, 3), which has a score of (8 + 7 + 4) - (6 + 5 + 3) = 5.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

#region using
using System;
using System.Collections.Generic;
using System.Linq;
using IEnumerable = System.Collections.IEnumerable;
using IEnumerator = System.Collections.IEnumerator;
using BitArray = System.Collections.BitArray;
using BigInteger = System.Numerics.BigInteger;
using TextReader = System.IO.TextReader;
using System.Text;
#endregion

namespace AtCoderProject
{
    public class Program
    {
        public object Calc()
        {
            var N = consoleReader.Int;
            var a = consoleReader.Split.Long;
            var dpSmall = new long[N + 1];
            var dpLarge = new long[N + 1];


            var large = new SortedCollection<long>(a.Take(N));

            var small = new SortedCollection<long>(a.Skip(2 * N), Comparer<long>.Create((l, r) => r.CompareTo(l)));

            dpLarge[0] = large.Sum();
            dpSmall[N] = small.Sum();

            for (int i = 0; i < N; i++)
            {
                var nextL = a[N + i];
                long min = large.First;
                if (min < nextL)
                {
                    large.Add(nextL);
                    large.Remove(min);
                    dpLarge[i + 1] = dpLarge[i] + nextL - min;
                }
                else
                    dpLarge[i + 1] = dpLarge[i];

                var nextR = a[2 * N - i - 1];
                var max = small.First;
                if (nextR < max)
                {
                    small.Add(nextR);
                    small.Remove(max);
                    dpSmall[N - i - 1] = dpSmall[N - i] + nextR - max;
                }
                else
                    dpSmall[N - i - 1] = dpSmall[N - i];
            }
            return Enumerable.Zip(dpLarge, dpSmall, (l, s) => l - s).Max();
        }

        class SortedCollection<T> : ICollection<T>
        {
            SortedDictionary<T, int> dic;
            public T First => dic.Keys.First();
            public SortedCollection() : this(Comparer<T>.Default) { }
            public SortedCollection(IComparer<T> comparer) { dic = new SortedDictionary<T, int>(comparer); }
            public SortedCollection(IEnumerable<T> original) : this(original, Comparer<T>.Default) { }
            public SortedCollection(IEnumerable<T> original, IComparer<T> comparer) : this(comparer)
            {
                foreach (var item in original)
                    this.Add(item);
            }

            public bool IsReadOnly => false;
            public int Count { get; private set; } = 0;
            public void Add(T item)
            {
                if (dic.ContainsKey(item)) ++dic[item];
                else dic[item] = 1;
                Count++;
            }
            public void Clear() => dic.Clear();
            public bool Contains(T item) => dic.ContainsKey(item);
            public void CopyTo(T[] array, int arrayIndex) { throw new NotImplementedException(); }

            public bool Remove(T item)
            {
                int count;
                if (dic.TryGetValue(item, out count))
                {
                    Count--;
                    if (count > 1) --dic[item];
                    else dic.Remove(item);
                    return true;
                }
                else
                    return false;
            }

            IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
            public IEnumerator<T> GetEnumerator()
            {
                foreach (var pair in dic)
                    foreach (var item in Enumerable.Repeat(pair.Key, pair.Value))
                        yield return item;
            }
        }

        #region いつもの
#pragma warning disable
        private ConsoleReader consoleReader;
        public Program(ConsoleReader consoleReader) { this.consoleReader = consoleReader; }
        static void Main() => Console.WriteLine(new Program(new ConsoleReader(Console.In)).Calc()); static string AllLines<T>(IEnumerable<T> source) => string.Join("\n", source);
    }
    static class Ext
    {
        public static Dictionary<TKey, int> GroupCount<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) => source.GroupBy(keySelector).ToDictionary(g => g.Key, g => g.Count());
        public static Dictionary<TKey, int> GroupCount<TKey>(this IEnumerable<TKey> source) => source.GroupCount(i => i);
    }
    public class ConsoleReader { private string[] ReadLineSplit() => textReader.ReadLine().Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries); private string[] line = Array.Empty<string>(); private int linePosition; private TextReader textReader; public ConsoleReader(TextReader tr) { textReader = tr; } public int Int => int.Parse(String); public long Long => long.Parse(String); public double Double => double.Parse(String); public string String { get { if (linePosition >= line.Length) { linePosition = 0; line = ReadLineSplit(); } return line[linePosition++]; } } public class SplitLine { private string[] splited; public SplitLine(ConsoleReader cr) { splited = cr.ReadLineSplit(); cr.line = Array.Empty<string>(); } public int[] Int => String.Select(x => int.Parse(x)).ToArray(); public int[] Int0 => String.Select(x => int.Parse(x) - 1).ToArray(); public long[] Long => String.Select(x => long.Parse(x)).ToArray(); public double[] Double => String.Select(x => double.Parse(x)).ToArray(); public string[] String => splited; } public SplitLine Split => new SplitLine(this); public class RepeatReader : IEnumerable<ConsoleReader> { ConsoleReader cr; int count; public RepeatReader(ConsoleReader cr, int count) { this.cr = cr; this.count = count; } public IEnumerator<ConsoleReader> GetEnumerator() => Enumerable.Repeat(cr, count).GetEnumerator(); System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerable<string> String => this.Select(cr => cr.String); public IEnumerable<int> Int => this.Select(cr => cr.Int); public IEnumerable<int> Int0 => this.Select(cr => cr.Int - 1); public IEnumerable<long> Long => this.Select(cr => cr.Long); public IEnumerable<double> Double => this.Select(cr => cr.Double); } public RepeatReader Repeat(int count) => new RepeatReader(this, count); }
    #endregion
}