import std.stdio, std.conv, std.string, std.bigint; import std.math, std.random, std.datetime; import std.array, std.range, std.algorithm, std.container, std.format; string read(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; } class Node{ int id; real value; Node trigger; int count; bool isFull = 0; bool isVisited = 0; this(int id){ this.id = id; } override string toString(){ return "#" ~ id.to!string ~ " => #" ~ (trigger? trigger.id.to!string: "*") ~ " " ~ count.to!string ~ " (" ~ value.format!"%0.1f" ~ ")" ~ (isVisited? (isFull? "": " H"): " ?"); } } void main(){ int n = read.to!int; Node[] nodes; foreach(i; 0 .. n) nodes ~= new Node(i); foreach(i; 0 .. n){ Node nd = nodes[i]; nd.value = read.to!real; nd.trigger = nodes[read.to!int - 1]; nd.trigger.count += 1; } debug foreach(nd; nodes) nd.writeln; // 盲腸部分は半減を適用できる foreach(nd; nodes) if(! nd.isVisited) for(Node nd1 = nd; nd1.count == 0; nd1 = nd1.trigger){ nd1.isVisited = 1; nd1.trigger.count -= 1; } debug foreach(nd; nodes) nd.writeln; // ループ部分(複数の場合もあり)は1つを除き半減を適用できる foreach(nd; nodes) if(! nd.isVisited){ Node bestnd = nd; for(Node nd1 = nd; ! nd1.isVisited; nd1 = nd1.trigger){ nd1.isVisited = 1; if(bestnd.value > nd1.value) bestnd = nd1; } bestnd.isFull= 1; } debug foreach(nd; nodes) nd.writeln; // 集計 real sum = 0.0; foreach(nd; nodes) if(nd.isFull) sum += nd.value; else sum += nd.value / 2.0; sum.format!"%0.1f".writeln; }