using System; using System.Collections.Generic; using System.Linq; class Program { static string InputPattern = "InputX"; static List GetInputList() { var WillReturn = new List(); if (InputPattern == "Input1") { WillReturn.Add("6"); WillReturn.Add("3 2 1 1 2 3"); //3 3 3 3 3 3 } else if (InputPattern == "Input2") { WillReturn.Add("6"); WillReturn.Add("3 1 10 3 10 2"); //3 3 10 10 10 2 } else if (InputPattern == "Input3") { WillReturn.Add("6"); WillReturn.Add("1 3 10 1 10 2"); //1 3 10 10 10 2 } else { string wkStr; while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr); } return WillReturn; } class RangeInfoDef { internal int RangeSta; internal int RangeEnd; } static void Main() { List InputList = GetInputList(); int[] AArr = InputList[1].Split(' ').Select(pX => int.Parse(pX)).ToArray(); int LeafCnt = AArr.Length; var InsLazySegmentTree = new LazySegmentTree(LeafCnt, long.MaxValue); var RangeDict = new Dictionary(); for (int I = 0; I <= AArr.GetUpperBound(0); I++) { if (RangeDict.ContainsKey(AArr[I]) == false) { RangeDict[AArr[I]] = new RangeInfoDef(); RangeDict[AArr[I]].RangeSta = I; } RangeDict[AArr[I]].RangeEnd = I; } foreach (var EachPair in RangeDict.OrderBy(pX => pX.Key)) { InsLazySegmentTree.Internal_RangeUpdate( EachPair.Value.RangeSta, EachPair.Value.RangeEnd, EachPair.Key); } var AnswerList = new List(); for (int I = 0; I <= AArr.GetUpperBound(0); I++) { long MinVal = InsLazySegmentTree[I]; AnswerList.Add(MinVal); } string[] AnswerArr = Array.ConvertAll(AnswerList.ToArray(), pX => pX.ToString()); Console.WriteLine(string.Join(" ", AnswerArr)); } } #region LazySegmentTree // LazySegmentTreeクラス (RMinQ and RUQ) internal class LazySegmentTree { private long[] mTreeNodeArr; private long UB; // 木のノードの配列のUB private long mLeafCnt; // 葉ノードの数 private long mExternalArrUB; private long?[] mLazyArr; // 遅延配列 // ノードの添字を引数とし、範囲の開始添字と終了添字を持つ配列 private struct RangeInfoDef { internal long StaInd; internal long EndInd; } private RangeInfoDef[] mRangeInfo; // ノードのIndexの列挙を返す internal IEnumerable GetNodeIndEnum() { for (long I = 0; I <= mExternalArrUB; I++) { yield return I; } } // 木のノードのUBを返す internal long GetUB() { return mExternalArrUB; } // コンストラクタその1 // 引数1 外部IndのUB // 引数2 単位元 internal LazySegmentTree(long pExternalArrUB, long pInitVal) { mExternalArrUB = pExternalArrUB; ConstructorTreeInit(); // すべての値をpInitValに for (long I = 0; I <= UB; I++) { mTreeNodeArr[I] = pInitVal; } } // コンストラクタその2 // 引数1 初期化用の配列 // 引数2 単位元 internal LazySegmentTree(long[] pInitArr, long pInitVal) { mExternalArrUB = pInitArr.GetUpperBound(0); ConstructorTreeInit(); // すべての値をpInitValに for (long I = 0; I <= UB; I++) { mTreeNodeArr[I] = pInitVal; } for (long I = 0; I <= pInitArr.GetUpperBound(0); I++) { long TreeNode = DeriveTreeNode(I); mTreeNodeArr[TreeNode] = pInitArr[I]; } // 木DPの要領で、葉から根に伝播 ExecTreeDP(); } // コンストラクタその3 // 引数1 初期化用のList // 引数2 単位元 internal LazySegmentTree(List pInitList, long pInitVal) { mExternalArrUB = pInitList.Count - 1; ConstructorTreeInit(); // すべての値をpInitValに for (long I = 0; I <= UB; I++) { mTreeNodeArr[I] = pInitVal; } for (long I = 0; I <= pInitList.Count - 1; I++) { long TreeNode = DeriveTreeNode(I); mTreeNodeArr[TreeNode] = pInitList[(int)I]; } // 木DPの要領で、葉から根に伝播 ExecTreeDP(); } // コンストラクタのヘルパメソッド(木の初期化) private void ConstructorTreeInit() { // 簡単のため、葉ノード数を2のべき乗に long ArrLength = 0; for (long I = 1; I < long.MaxValue; I *= 2) { ArrLength += I; mLeafCnt = I; if (mExternalArrUB + 1 < mLeafCnt) break; } UB = ArrLength - 1; mTreeNodeArr = new long[UB + 1]; // 遅延配列を初期化 mLazyArr = new long?[UB + 1]; // ノードの添字を引数とし、範囲の開始添字と終了添字を持つ配列の作成 mRangeInfo = new RangeInfoDef[UB + 1]; for (long I = 0; I <= UB; I++) { if (I == 0) { RangeInfoDef WillSet1; WillSet1.StaInd = 0; WillSet1.EndInd = mLeafCnt - 1; mRangeInfo[I] = WillSet1; continue; } long ParentNode = DeriveParentNode(I); RangeInfoDef ParentRangeInfo = mRangeInfo[ParentNode]; RangeInfoDef WillSet2; long Mid = (ParentRangeInfo.StaInd + ParentRangeInfo.EndInd) / 2; if (I % 2 == 1) { // 奇数ノードの場合 WillSet2.StaInd = ParentRangeInfo.StaInd; WillSet2.EndInd = Mid; } else { // 偶数ノードの場合 WillSet2.StaInd = Mid + 1; WillSet2.EndInd = ParentRangeInfo.EndInd; } mRangeInfo[I] = WillSet2; } } // 木DPの要領で、葉から根に伝播 private void ExecTreeDP() { for (long I = UB; 0 < I; I--) { long SendNode = DeriveParentNode(I); mTreeNodeArr[SendNode] = Math.Min(mTreeNodeArr[SendNode], mTreeNodeArr[I]); } } // インデクサ internal long this[long pInd] { get { return Internal_Query(pInd, pInd); } set { Internal_RangeUpdate(pInd, pInd, value); } } // 親ノードの添字を取得 private long DeriveParentNode(long pTarget) { return (pTarget - 1) / 2; } // 子ノードの添字(小さいほう)を取得 private long DeriveChildNode(long pTarget) { return pTarget * 2 + 1; } // 葉ノードの配列の添字を木の添字に変換して返す private long DeriveTreeNode(long pLeafArrInd) { long BaseInd = UB - mLeafCnt + 1; return BaseInd + pLeafArrInd; } // カレントノードを引数として、遅延評価を行う private void LazyEval(long pCurrNode) { // 遅延配列が空なら何もしない if (mLazyArr[pCurrNode].HasValue == false) return; // 遅延配列の値を反映する mTreeNodeArr[pCurrNode] = mLazyArr[pCurrNode].Value; long ChildNode1 = DeriveChildNode(pCurrNode); long ChildNode2 = ChildNode1 + 1; if (ChildNode1 <= UB) { mLazyArr[ChildNode1] = mLazyArr[pCurrNode].Value; } if (ChildNode2 <= UB) { mLazyArr[ChildNode2] = mLazyArr[pCurrNode].Value; } // 伝播が終わったので、自ノードの遅延配列を空にする mLazyArr[pCurrNode] = null; } // 開始添字と終了添字とカレントノードを引数として、区間更新を行う internal void Internal_RangeUpdate(long pSearchStaInd, long pSearchEndInd, long pUpdateVal) { Private_RangeUpdate(pSearchStaInd, pSearchEndInd, pUpdateVal, 0); } private void Private_RangeUpdate(long pSearchStaInd, long pSearchEndInd, long pUpdateVal, long pCurrNode) { // カレントノードの遅延評価を行う LazyEval(pCurrNode); long CurrNodeStaInd = mRangeInfo[pCurrNode].StaInd; long CurrNodeEndInd = mRangeInfo[pCurrNode].EndInd; // OverLapしてなければ、何もしない if (CurrNodeEndInd < pSearchStaInd || pSearchEndInd < CurrNodeStaInd) { return; } // 完全に含んでいれば、遅延配列に値を入れた後に評価 if (pSearchStaInd <= CurrNodeStaInd && CurrNodeEndInd <= pSearchEndInd) { mLazyArr[pCurrNode] = pUpdateVal; LazyEval(pCurrNode); return; } // そうでなければ、2つの区間に再帰呼出し long ChildNode1 = DeriveChildNode(pCurrNode); long ChildNode2 = ChildNode1 + 1; Private_RangeUpdate(pSearchStaInd, pSearchEndInd, pUpdateVal, ChildNode1); Private_RangeUpdate(pSearchStaInd, pSearchEndInd, pUpdateVal, ChildNode2); // カレントノードの更新 mTreeNodeArr[pCurrNode] = Math.Min(mTreeNodeArr[ChildNode1], mTreeNodeArr[ChildNode2]); } // 開始添字と終了添字とカレントノードを引数として、最小値を返す internal long Internal_Query(long pSearchStaInd, long pSearchEndInd) { return Private_Query(pSearchStaInd, pSearchEndInd, 0); } private long Private_Query(long pSearchStaInd, long pSearchEndInd, long pCurrNode) { // 該当ノードを遅延評価する LazyEval(pCurrNode); long CurrNodeStaInd = mRangeInfo[pCurrNode].StaInd; long CurrNodeEndInd = mRangeInfo[pCurrNode].EndInd; // OverLapしてなければ、long.MaxValue if (CurrNodeEndInd < pSearchStaInd || pSearchEndInd < CurrNodeStaInd) return long.MaxValue; // 完全に含んでいれば、このノードの値 if (pSearchStaInd <= CurrNodeStaInd && CurrNodeEndInd <= pSearchEndInd) return mTreeNodeArr[pCurrNode]; // そうでなければ、2つの子の最小値 long ChildNode1 = DeriveChildNode(pCurrNode); long ChildNode2 = ChildNode1 + 1; long ChildVal1 = Private_Query(pSearchStaInd, pSearchEndInd, ChildNode1); long ChildVal2 = Private_Query(pSearchStaInd, pSearchEndInd, ChildNode2); return Math.Min(ChildVal1, ChildVal2); } internal void DebugPrint() { for (long I = 0; I <= UB; I++) { if (mLazyArr[I].HasValue) { Console.WriteLine("mTreeNodeArr[{0}] = {1} , mLazyArr[{0}] = {2}", I, mTreeNodeArr[I], mLazyArr[I]); } else { Console.WriteLine("mTreeNodeArr[{0}] = {1}", I, mTreeNodeArr[I]); } } } } #endregion