AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC040-D 道路の老朽化対策について
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 4");
WillReturn.Add("1 2 2000");
WillReturn.Add("2 3 2004");
WillReturn.Add("3 4 1999");
WillReturn.Add("4 5 2001");
WillReturn.Add("3");
WillReturn.Add("1 2000");
WillReturn.Add("1 1999");
WillReturn.Add("3 1995");
//1
//3
//5
}
else if (InputPattern == "Input2") {
WillReturn.Add("4 5");
WillReturn.Add("1 2 2005");
WillReturn.Add("3 1 2001");
WillReturn.Add("3 4 2002");
WillReturn.Add("1 4 2004");
WillReturn.Add("4 2 2003");
WillReturn.Add("5");
WillReturn.Add("1 2003");
WillReturn.Add("2 2003");
WillReturn.Add("1 2001");
WillReturn.Add("3 2003");
WillReturn.Add("4 2004");
//3
//3
//4
//1
//1
}
else if (InputPattern == "Input3") {
WillReturn.Add("4 5");
WillReturn.Add("1 2 10");
WillReturn.Add("1 2 1000");
WillReturn.Add("2 3 10000");
WillReturn.Add("2 3 100000");
WillReturn.Add("3 1 200000");
WillReturn.Add("4");
WillReturn.Add("1 0");
WillReturn.Add("2 10000");
WillReturn.Add("3 100000");
WillReturn.Add("4 0");
//3
//3
//2
//1
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
struct QueryInfoDef
{
internal string Type;
internal int Year;
internal int P1;
internal int P2;
}
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => int.Parse(pX)).ToArray();
SplitAct(InputList[0]);
int N = wkArr[0];
int M = wkArr[1];
var QueryInfoList = new List<QueryInfoDef>();
foreach (string EachStr in InputList.Skip(1).Take(M)) {
SplitAct(EachStr);
QueryInfoDef WillAdd;
WillAdd.Type = "Unite";
WillAdd.Year = wkArr[2];
WillAdd.P1 = wkArr[0];
WillAdd.P2 = wkArr[1];
QueryInfoList.Add(WillAdd);
}
int KokuminNo = 1;
foreach (string EachStr in InputList.Skip(1 + M + 1)) {
SplitAct(EachStr);
QueryInfoDef WillAdd;
WillAdd.Type = "GetSize";
WillAdd.Year = wkArr[1];
WillAdd.P1 = wkArr[0];
WillAdd.P2 = KokuminNo++;
QueryInfoList.Add(WillAdd);
}
var Query1 = QueryInfoList.OrderByDescending(pX => pX.Year);
var Query2 = Query1.ThenBy(pX => (pX.Type == "GetSize") ? 0 : 1);
QueryInfoList = Query2.ToList();
var InsUnionFindSizeInfo = new UnionFindSizeInfo();
for (int I = 1; I <= N; I++) {
InsUnionFindSizeInfo.MakeSet(I);
}
// 訪問可能ノード数[国民] なDict
var AnswerDict = new Dictionary<int, long>();
foreach (QueryInfoDef EachQueryInfo in QueryInfoList) {
if (EachQueryInfo.Type == "Unite") {
InsUnionFindSizeInfo.Unite(EachQueryInfo.P1, EachQueryInfo.P2);
}
if (EachQueryInfo.Type == "GetSize") {
AnswerDict[EachQueryInfo.P2] = InsUnionFindSizeInfo.GetSize(EachQueryInfo.P1);
}
}
foreach (var EachPair in AnswerDict.OrderBy(pX => pX.Key)) {
Console.WriteLine(EachPair.Value);
}
}
}
// UnionFindSizeInfoクラス
internal class UnionFindSizeInfo
{
private class NodeInfoDef
{
internal long ParentNode;
internal long Rank;
internal long Size;
}
private Dictionary<long, NodeInfoDef> mNodeInfoDict =
new Dictionary<long, NodeInfoDef>();
// 要素が1つである木を森に追加
internal void MakeSet(long pNode)
{
NodeInfoDef WillAdd = new NodeInfoDef();
WillAdd.ParentNode = pNode;
WillAdd.Rank = 0;
WillAdd.Size = 1;
mNodeInfoDict[pNode] = WillAdd;
}
// 合併処理
internal void Unite(long pX, long pY)
{
long XNode = FindSet(pX);
long YNode = FindSet(pY);
// 既に同じ木の場合
if (XNode == YNode) return;
long XRank = mNodeInfoDict[XNode].Rank;
long YRank = mNodeInfoDict[YNode].Rank;
if (XRank > YRank) {
mNodeInfoDict[YNode].ParentNode = XNode;
mNodeInfoDict[XNode].Size += mNodeInfoDict[YNode].Size;
}
else {
mNodeInfoDict[XNode].ParentNode = YNode;
mNodeInfoDict[YNode].Size += mNodeInfoDict[XNode].Size;
if (XRank == YRank) {
mNodeInfoDict[YNode].Rank++;
}
}
}
// ノードを引数として、木の根を取得
internal long FindSet(long pTargetNode)
{
// 根までの経路上のノードのList
var PathNodeList = new List<long>();
long CurrNode = pTargetNode;
while (CurrNode != mNodeInfoDict[CurrNode].ParentNode) {
PathNodeList.Add(CurrNode);
CurrNode = mNodeInfoDict[CurrNode].ParentNode;
}
// 経路圧縮 (親ポインタの付け替え)
foreach (long EachPathNode in PathNodeList) {
NodeInfoDef wkNodeInfo = mNodeInfoDict[EachPathNode];
wkNodeInfo.ParentNode = CurrNode;
mNodeInfoDict[EachPathNode] = wkNodeInfo;
}
return CurrNode;
}
// ノードを引数として、木のサイズを取得
internal long GetSize(long pNode)
{
long RootNode = FindSet(pNode);
return mNodeInfoDict[RootNode].Size;
}
internal void DebugPrint()
{
foreach (var EachPair in mNodeInfoDict.OrderBy(pX => pX.Key)) {
Console.WriteLine("mNodeInfoDict[{0}].ParentNode={1}",
EachPair.Key, EachPair.Value.ParentNode);
}
}
}
解説
UnionFindで
クエリを年の降順に処理してます。