AtCoderのABC    次のABCの問題へ    前のABCの問題へ

ABC465-C Reverse Permutation


問題へのリンク


C#のソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("5");
            WillReturn.Add("ooxoo");
            //5 2 1 3 4
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("7");
            WillReturn.Add("ooooooo");
            //7 5 3 1 2 4 6
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("15");
            WillReturn.Add("xooxoxoxoxoxxoo");
            //15 11 10 7 6 3 1 2 4 5 8 9 12 13 14
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static long[] GetSplitArr(string pStr)
    {
        return (pStr == "" ? new string[0] : pStr.Split(' ')).Select(pX => long.Parse(pX)).ToArray();
    }

    static void Main()
    {
        List<string> InputList = GetInputList();

        long N = long.Parse(InputList[0]);
        string S = InputList[1];
        char[] CharArr = S.ToCharArray();
        long UB = CharArr.GetUpperBound(0);

        // ImplicitTreapでの区間反転を行う場合、
        // 0オリジンでデータを持つ必要があるようです
        var InsImplicitTreap = new ImplicitTreap();
        for (long I = 1; I <= N; I++) {
            InsImplicitTreap.internal_insert(I - 1, I);
        }

        for (long I = 0; I <= UB; I++) {
            if (CharArr[I] == 'o') {
                long RangeSta = 0;
                long RangeEnd = I;
                InsImplicitTreap.internal_reverse(RangeSta, RangeEnd);
            }
        }
        var ValList = InsImplicitTreap.internal_GetValList();
        Console.WriteLine(LongEnumJoin(" ", ValList));
    }

    // セパレータとLong型の列挙を引数として、結合したstringを返す
    static string LongEnumJoin(string pSeparater, IEnumerable<long> pEnum)
    {
        string[] StrArr = Array.ConvertAll(pEnum.ToArray(), pX => pX.ToString());
        return string.Join(pSeparater, StrArr);
    }

}

#region ImplicitTreap
internal class ImplicitTreap
{
    const long INF = long.MaxValue;
    static private Random rnd = new Random();
    private class Node
    {
        internal long value;
        internal long min;
        internal long lazy;
        internal long priority;
        internal long cnt;
        internal bool rev;
        internal Node l;
        internal Node r;

        // コンストラクタ
        internal Node(long value, long priority)
        {
            this.value = value;
            this.min = INF;
            this.lazy = 0;
            this.priority = priority;
            this.cnt = 1;
            this.rev = false;
            this.l = null;
            this.r = null;
        }
    }
    Node root = null;

    private long private_cnt(Node t)
    {
        return (t != null) ? t.cnt : 0;
    }

    private long private_get_min(Node t)
    {
        return (t != null) ? t.min : INF;
    }

    private void private_update_cnt(Node t)
    {
        if ((t != null)) {
            t.cnt = 1 + private_cnt(t.l) + private_cnt(t.r);
        }
    }

    private void private_update_min(Node t)
    {
        if ((t != null)) {
            t.min = Math.Min(t.value, Math.Min(private_get_min(t.l), private_get_min(t.r)));
        }
    }

    private void private_pushup(Node t)
    {
        private_update_cnt(t); private_update_min(t);
    }

    private void private_pushdown(Node t)
    {
        if ((t != null) && (t.rev)) {
            t.rev = false;
            private_swap(ref (t.l), ref (t.r));
            if ((t.l) != null) t.l.rev = (t.l.rev == false);
            if ((t.r) != null) t.r.rev = (t.r.rev == false);
        }
        if ((t != null) && (t.lazy != 0)) {
            if ((t.l) != null) {
                t.l.lazy += t.lazy;
                t.l.min += t.lazy;
            }
            if ((t.r) != null) {
                t.r.lazy += t.lazy;
                t.r.min += t.lazy;
            }
            t.value += t.lazy;
            t.lazy = 0;
        }
        private_pushup(t);
    }

    private void private_split(Node t, long key, ref Node l, ref Node r)
    {
        if (t == null) {
            l = r = null;
            return;
        }
        private_pushdown(t);
        long implicit_key = private_cnt(t.l) + 1;
        if (key < implicit_key) {
            private_split(t.l, key, ref l, ref t.l); r = t;
        }
        else {
            private_split(t.r, key - implicit_key, ref t.r, ref r); l = t;
        }
        private_pushup(t);
    }

    private void private_insert(ref Node t, long key, Node item)
    {
        Node t1 = null;
        Node t2 = null;
        private_split(t, key, ref t1, ref t2);
        private_merge(ref t1, t1, item);
        private_merge(ref t, t1, t2);
    }

    private void private_merge(ref Node t, Node l, Node r)
    {
        private_pushdown(l);
        private_pushdown(r);
        if (l == null || r == null) {
            t = ((l != null) ? l : r);
        }
        else if (l.priority > r.priority) {
            private_merge(ref l.r, l.r, r); t = l;
        }
        else {
            private_merge(ref r.l, l, r.l); t = r;
        }
        private_pushup(t);
    }

    private void private_erase(ref Node t, long key)
    {
        Node t1 = null, t2 = null, t3 = null;
        private_split(t, key + 1, ref t1, ref t2);
        private_split(t1, key, ref t1, ref t3);
        private_merge(ref t, t1, t2);
    }

    private void private_add(Node t, long l, long r, long x)
    {
        Node t1 = null, t2 = null, t3 = null;
        private_split(t, l, ref t1, ref t2);
        private_split(t2, r - l, ref t2, ref t3);
        t2.lazy += x;
        t2.min += x;
        private_merge(ref t2, t2, t3);
        private_merge(ref t, t1, t2);
    }

    private long private_findmin(Node t, long l, long r)
    {
        Node t1 = null, t2 = null, t3 = null;
        private_split(t, l, ref t1, ref t2);
        private_split(t2, r - l, ref t2, ref t3);
        long ret = t2.min;
        private_merge(ref t2, t2, t3);
        private_merge(ref t, t1, t2);
        return ret;
    }

    private void private_reverse(Node t, long l, long r)
    {
        if (l > r) return;
        Node t1 = null, t2 = null, t3 = null;
        private_split(t, l, ref t1, ref t2);
        private_split(t2, r - l, ref t2, ref t3);
        t2.rev = (t2.rev == false);
        private_merge(ref t2, t2, t3);
        private_merge(ref t, t1, t2);
    }

    // [l, r)の先頭がmになるように左シフトさせる。std::rotateと同じ仕様
    private void private_rotate(Node t, long l, long m, long r)
    {
        private_reverse(t, l, r);
        private_reverse(t, l, l + r - m);
        private_reverse(t, l + r - m, r);
    }

    private void private_dump(Node t)
    {
        if (t == null) return;
        private_pushdown(t);
        private_dump(t.l);
        Console.Write("{0} ", t.value);
        private_dump(t.r);
    }

    private void private_GetValList(Node t)
    {
        if (t == null) return;
        private_pushdown(t);
        private_GetValList(t.l);
        mValList.Add(t.value);
        private_GetValList(t.r);
    }

    private void private_swap(ref Node p1, ref Node p2)
    {
        Node tmp = p1;
        p1 = p2;
        p2 = tmp;
    }

    // 指定Indに値を追加
    internal void internal_insert(long pos, long x)
    {
        private_insert(ref root, pos, new Node(x, rnd.Next()));
    }

    // 閉区間[l,r]に値を加算
    internal void internal_add(long l, long r, long x)
    {
        r++; // 閉区間に変更
        private_add(root, l, r, x);
    }

    // 閉区間[l,r]の最小値を取得
    internal long internal_findmin(long l, long r)
    {
        r++; // 閉区間に変更
        return private_findmin(root, l, r);
    }

    // 指定Indを消す
    internal void internal_erase(long pos)
    {
        private_erase(ref root, pos);
    }

    // 閉区間[l,r]を反転
    internal void internal_reverse(long l, long r)
    {
        r++; // 閉区間に変更
        private_reverse(root, l, r);
    }

    // [l, r]の先頭がmになるように左シフト。std::rotateと同じ仕様
    internal void internal_rotate(long l, long m, long r)
    {
        r++; // 閉区間に変更
        private_rotate(root, l, m, r);
    }

    // デバッグ表示
    internal void internal_dump()
    {
        private_dump(root);
        Console.WriteLine();
    }

    // 値のListを返す
    private List<long> mValList = new List<long>();
    internal List<long> internal_GetValList()
    {
        mValList.Clear();
        private_GetValList(root);
        return mValList;
    }
}
#endregion


解説

ImplicitTreapを使用してます。
ImplicitTreapでの区間反転を行う場合、
0オリジンでデータを持つ必要があるようです。