// Arup Guha
// 6/6/2016
// Solution to 2016 NAIPC Problem J: Whiteboard

import java.util.*;
import java.io.*;

public class j {
    
    final public static int[] DX = {1,0,-1,0};
    final public static int[] DY = {0,1,0,-1};
    
    public static int r;
    public static int c;
    public static boolean[][] grid;
    public static int[][] moves;
    public static long[] tList;
    public static int[][] loc;
    
    public static IntTree[] rowTree;
    public static IntTree[] colTree;
    
    public static void main(String[] args) throws Exception {
        
        // Set up
        BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer tok = new StringTokenizer(stdin.readLine());
        r = Integer.parseInt(tok.nextToken());
        c = Integer.parseInt(tok.nextToken());
        int numCommands = Integer.parseInt(tok.nextToken());
        moves = new int[numCommands][2];
        tList = new long[numCommands+1];
        loc = new int[numCommands+1][2];
        
        // Read in the grid.
        grid = new boolean[r][c];
        for (int i=r-1; i>=0; i--) {
            String s = stdin.readLine();
            for (int j=0; j<c; j++)
                grid[i][j] = (s.charAt(j) == '#');
        }
        
        // Just store commands for now, storing where we are at the beginning of each command.
        tList[0] = 1;
        for (int i=0; i<numCommands; i++) {
            tok = new StringTokenizer(stdin.readLine());
            moves[i][0] = convert(tok.nextToken());
            moves[i][1] = Integer.parseInt(tok.nextToken());
            tList[i+1] = tList[i] + moves[i][1];
            loc[i+1] = move(loc[i], moves[i]);
        }
        
        // Set up "interval" trees.
        rowTree = new IntTree[r];
        for (int i=0; i<r; i++)
            rowTree[i] = new IntTree(0,c-1);
        colTree = new IntTree[c];
        for (int i=0; i<c; i++)
            colTree[i] = new IntTree(0, r-1);
        
        // Fill appropriate interval tree for each command.
        for (int i=0; i<numCommands; i++) {
            
            // Moving in one column, fill column tree.
            if (moves[i][0]%2 == 0) {
                int minx = Math.min(loc[i][0], loc[i+1][0]);
                int maxx = Math.max(loc[i][0], loc[i+1][0]);
                colTree[loc[i][1]].fill(minx, maxx, i);
            }
            
            // Moving in one row.
            else {
                int miny = Math.min(loc[i][1], loc[i+1][1]);
                int maxy = Math.max(loc[i][1], loc[i+1][1]);
                rowTree[loc[i][0]].fill(miny, maxy, i);
            }
        }
        
        // Store the latest time each square was visited in res. Must look at both sets of "interval trees",
        // since for each movement, only one of two possible trees is marked.
        int[][] res = new int[r][c];
        for (int i=0; i<r; i++)
            rowTree[i].query(res[i]);
        for (int j=0; j<c; j++) {
            int[] col = new int[r];
            colTree[j].query(col);
            for (int i=0; i<r; i++)
                res[i][j] = Math.max(res[i][j],col[i]);
        }
        
        // Here are out answers.
        long earliest = 0;
        long latest = tList[numCommands];
        boolean okay = true;
        
        // Just go to each square.
        for (int i=0; i<r; i++) {
            for (int j=0; j<c; j++) {
            	
            	// Impossible if we never got here and there's a mark.
                if (res[i][j] == -1 && grid[i][j]) {
                    okay = false;
                    break;
                }
                
                // These are unmarked, untouched squares, they don't help us.
                if (res[i][j] == -1) continue;
                
                // Find the last time this square was touched and update accordingly.
                long t = getTime(res[i][j], i, j);
                if (grid[i][j]) earliest = Math.max(earliest, t);
                if (!grid[i][j]) latest = Math.min(latest, t-1);
            }
            
            // Get out.
            if (!okay) break;
        }
        
        // Output result.
        if (okay && earliest <= latest)
            System.out.println(earliest+" "+latest);
        else
            System.out.println("-1 -1");
    }
    
    // Returns the time step we're at position (x,y) for command tStep.
    public static long getTime(int tStep, int x, int y) {
        return tList[tStep] + Math.abs(loc[tStep][0]-x) + Math.abs(loc[tStep][1]-y);
    }
    
    public static int convert(String s) {
        if (s.equals("up")) return 0;
        else if (s.equals("right")) return 1;
        else if (s.equals("down")) return 2;
        return 3;
    }
    
    public static int[] move(int[] cur, int[] move) {
        int[] res = new int[2];
        res[0] = cur[0] + move[1]*DX[move[0]];
        res[1] = cur[1] + move[1]*DY[move[0]];
        return res;
    }
}

/*** Not really an interval tree - keeps track of last item placed in each index from low to high ***/

class IntTree {

    // Stores range for this node.
    public int low;
    public int high;
        
    // Stores status of the whole range's first and last update.
    public boolean curUpdated;

    // Stores aggregate data for this node.
    public int last;

    // Pointers to children.
    public IntTree left;
    public IntTree right;

    // Creates an interval tree from myLow to myHigh, inclusive.
    public IntTree(int myLow, int myHigh) {

        low = myLow;
        high = myHigh;
		
        last = -1;
        curUpdated = true;

        // Lowest level.
        if (low == high) {
            left = null;
            right = null;
        }

        // Must create more nodes.
        else {
            int mid = (low+high)/2;
            left = new IntTree(low, mid);
            right = new IntTree(mid+1, high);
        }
    }

    // Changes the values in the range [start, end] to value.
    public void fill(int start, int end, int value) {

        // Out of range.
        if (high < start || end < low) return;

        // Whole range must be updated.
        if (start <= low && high <= end) {
            curUpdated = true;
            last = value;
            return;
        }
            
        else {
        	
        	// This is tricky - we must "push down" the correct answers to lower trees.
        	if (curUpdated) {
        		left.fill(low,start-1, last);
        		right.fill(low,start-1, last);
        		left.fill(end+1, high, last);
        		right.fill(end+1, high, last);
        	}
        	
        	// Our value here is no longer correct for the whole range.
            curUpdated = false;
        }

        // Continue down.
        left.fill(start, end, value);
        right.fill(start, end, value);
    }

    public void query(int[] arr) {

		// Just fill in all of these answers, as they are correct.
        if (curUpdated) {
            for (int i=low; i<=high; i++)
                arr[i] = last;
            return;
        }
            
        // Otherwise, get answers from below.
        left.query(arr);
        right.query(arr);
    }
}