Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Problem B:
Vector Field

In 20015, JAG (Jagan Acceleration Group) has succeeded in inventing a new accelerator named
Force Point for an experiment of proton collision on the two-dimensional $xy$-plane. If a proton
touches a Force Point, it is accelerated to twice its speed and its movement direction is veered. A
proton may be veered by a Force Field in four ways: the positive or negative directions parallel
to the $x$- or the $y$-axis. The direction in which a proton veers is determined by the type of the
Force Point. A Force Point can accelerate a proton only once because the Force Point disappears
immediately after the acceleration. Generating many Force Points on the two-dimensional plane,
which is called a 2D Force Point Field, allows us to accelerate a proton up to a target speed by
sequentially accelerating the proton with the Force Points in the 2D Force Point Filed.

The Force Point generation method is still under experiment and JAG has the following technical
limitations:

JAG cannot generate a Force Point with a specified position and a type.

JAG cannot generate a Force Point after putting a proton into a 2D Force Point Field.

JAG cannot move Force Points.

JAG cannot change a protons direction except by the effect of Force Points.

JAG can use only one proton for a 2D Force Point Field.

JAG can put a proton moving in any direction with its speed 1 at any position in a 2D
Force Point Field.

In order to achieve the maximum speed of a proton, the engineers at JAG have to choose the
optimal initial position and the optimal initial direction of the proton so that the proton is
accelerated by as many Force Points as possible, after carefully observing the generated 2D
Force Point Field.

By observing a generated 2D Force Point Field, the number of the generated Force Points is
known to be $n$. The position ($x_i$, $y_i$) and the direction veering type $d_i$ of the $i$-th point are
also known. Your task is to write a program to calculate the maximum speed of a proton by
acceleration on a given 2D Force Point Field when JAG puts a proton optimally.

Input

The input consists of a single test case which describes a 2D Force Point Field in the following
format.

$n$

$x_1$ $y_1$ $d_1$

...

$x_n$ $y_n$ $d_n$

The first line contains one integer $n$ ($1 \leq n \leq 3,000$) which is the number of the Force Points on
the 2D Force Point Field. Each of the next $n$ lines contains two integers $x_i$ and $y_i$ ($|x_i|$, $|y_i| \leq 10^9$)
and one character $d_i$ ($d_i$ is one of '>', 'v', '<' or '^'). $x_i$ and $y_i$ represent a coordinate of the $i$-th
Force Point, and $d_i$ is the direction veering type of the $i$-th force point. A force point with a type
'>' changes protons direction to the positive direction of the $x$-axis, 'v' represents the positive
direction of the $y$-axis, '<' represents the negative direction of the $x$-axis, and '^' represents the
negative direction of the $y$-axis. You can assume that any two Force Points are not generated
on the same coordinates.

Output

Display a line containing the integer $log_2 v_{max}$, where $v_{max}$ is the protons possible fastest speed.

Sample Input

9
0 0 v
1 0 >
2 0 <
0 1 >
1 1 v
2 1 v
0 2 ^
1 2 ^
2 2 <

Output for the Sample Input

9

The input looks like the following diagram. All the Force Points will disappear if you put a
proton at (1, 1).

v><
>vv
^^<

Sample Input

9
0 0 ^
1 0 ^
2 0 ^
0 1 <
1 1 ^
2 1 >
0 2 v
1 2 v
2 2 v

Output for the Sample Input

2

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Math;

public static class P
{
    static int N;
    static Cell[] Cells;
    public static void Main()
    {
        int n = int.Parse(Console.ReadLine());
        N = n;
        Dictionary<int, List<Tuple<int, int>>> yDict = new Dictionary<int, List<Tuple<int, int>>>();
        Dictionary<int, List<Tuple<int, int>>> xDict = new Dictionary<int, List<Tuple<int, int>>>();
        Cell[] cells = Enumerable.Repeat(new Cell() { DownInd = -1, LeftInd = -1, RightInd = -1, UpInd = -1 }, n).ToArray();
        for (int i = 0; i < n; i++)
        {
            var xyd = Console.ReadLine().Split();
            var x = int.Parse(xyd[1]);
            var y = int.Parse(xyd[0]);
            var dir = xyd[2] == "^" ? 0 : xyd[2] == ">" ? 1 : xyd[2] == "v" ? 2 : 3;
            cells[i].Dir = dir;
            if (!yDict.ContainsKey(y)) yDict.Add(y, new List<Tuple<int, int>>());
            if (!xDict.ContainsKey(x)) xDict.Add(x, new List<Tuple<int, int>>());
            yDict[y].Add(new Tuple<int, int>(x, i));
            xDict[x].Add(new Tuple<int, int>(y, i));
        }
        foreach (var key in xDict.Keys)
        {
            var val = xDict[key];
            val.Sort();
            for (int i = 0; i < val.Count - 1; i++)
            {
                cells[val[i].Item2].RightInd = val[i + 1].Item2;
                cells[val[i + 1].Item2].LeftInd = val[i].Item2;
            }
        }
        foreach (var key in yDict.Keys)
        {
            var val = yDict[key];
            val.Sort();
            for (int i = 0; i < val.Count - 1; i++)
            {
                cells[val[i].Item2].DownInd = val[i + 1].Item2;
                cells[val[i + 1].Item2].UpInd = val[i].Item2;
            }
        }
        int res = 0;
        for (int i = 0; i < n; i++)
        {
            Cells = cells.ToArray();
            res = Max(res, Simulate(i));
        }
        Console.WriteLine(res);
    }
    static void Remove(int ind)
    {
        var u = Cells[ind].UpInd;
        var d = Cells[ind].DownInd;
        var l = Cells[ind].LeftInd;
        var r = Cells[ind].RightInd;
        if (u != -1) Cells[u].DownInd = d;
        if (d != -1) Cells[d].UpInd = u;
        if (l != -1) Cells[l].RightInd = r;
        if (r != -1) Cells[r].LeftInd = l;
        Cells[ind] = new Cell() { Dir = -1 };
    }
    static int Simulate(int startInd)
    {
        int res = 0;
        var curCellInd = startInd;
        //List<int> path = new List<int>();
        while (true)
        {
            if (curCellInd == -1) break;
            //path.Add(curCellInd);
            int next;
            switch (Cells[curCellInd].Dir)
            {
                case 0:
                    next = Cells[curCellInd].UpInd;
                    break;
                case 1:
                    next = Cells[curCellInd].RightInd;
                    break;
                case 2:
                    next = Cells[curCellInd].DownInd;
                    break;
                case 3:
                    next = Cells[curCellInd].LeftInd;
                    break;
                default:
                    throw new Exception();
            }
            Remove(curCellInd);
            curCellInd = next;
            res++;
        }
        //Console.WriteLine($"begin at {startInd}:\n{string.Join("->", path)}");
        return res;
    }
}

struct Cell
{
    public int UpInd;
    public int DownInd;
    public int LeftInd;
    public int RightInd;
    public int Dir;
}