#include <stdio.h>
#include <vector>
#include <list>
#include <set>
#include <map>

using namespace std;

int debugLevel = 0;

#define DEBUGA(level, fmt, data...) if (level <= debugLevel) fprintf(stderr, fmt "\n", data);

/*
  colors used (least-significant 2 bits in RLE chunks):
    00 ('.') - empty (white)
	01 ('1') - fill (black)
	10 ('2') - fill2 (not used)
	11 ('#') - line (grey)
*/

const char UseChars[5] = ".12#";

#define BIGNUM long long

#define IS_C_EMPTY(c) (c==UseChars[0])
#define IS_C_FILL1(c) (c==UseChars[1])
#define IS_C_LINE(c)  (c==UseChars[3])

#define MAKE_COL(c) (c=='.' ? 0 : (c=='#' ? 3 : (c=='1' ? 1 : 2)))
#define MAKE_RUN(len, c) ((len << 2) | (c & 0x03))

#define GET_LEN(rl) (rl >> 2)
#define GET_CHAR(rl) (UseChars[rl & 0x03])


#define MAKE_FILLED(c)  (c |= 0x01)
#define MAKE_FILLED2(c) (c |= 0x02)
#define IS_EMPTY(c)   ((c & 0x03) == 0x00)
#define IS_FILLED(c)  ((c & 0x03) == 0x01)
#define IS_FILLED2(c) ((c & 0x03) == 0x02)
#define IS_LINE(c)    ((c & 0x03) == 0x03)


typedef set<int> Xcoords;
typedef vector<Xcoords> Ycoords;



class Row {
public:
	Row() : m_width(0) {}
	Row(int w) : m_width(w) { m_rle.push_back(MAKE_RUN(w, 0)); }

	int m_width;

	typedef vector<int> Rle;
	Rle m_rle;

	void setLinePixels(int n, Xcoords *xc) {
		m_rle.clear();
		int last=-1;
		int runLen=0;
		int b=0, w=0;
	
		// from beginning to last polygon segment
		for (Xcoords::iterator it = xc->begin(); it != xc->end(); ++it) {
			if (*it == last+1) {
				runLen++;
				last=*it;
			}
			else {
				if (runLen>0) m_rle.push_back(MAKE_RUN(runLen, 3));
				m_rle.push_back(MAKE_RUN(*it - last - 1,0));
				
				b+=runLen;
				w+=(*it - last - 1);
				
				runLen=1;
				last=*it;
			}
		}
		
		// from last polygon segment to n
		if (runLen>0) m_rle.push_back(MAKE_RUN(runLen, 3));
		m_rle.push_back(MAKE_RUN(n-last-1,0));
		w+=(n-last-1);
		
		m_width=n;
		DEBUGA(2, "Row: %d runs, %d:%d (line:empty) pixels", m_rle.size(), b, w);
    }
	
	void clear() {
		m_width = 0;
		m_rle.clear();
	}
	
	// returns rle encoded size
	int dump(FILE *f) {
		for (Rle::iterator it = m_rle.begin(); it != m_rle.end(); ++it) {
			int runLen = GET_LEN(*it);
			char c = GET_CHAR(*it);
			
			DEBUGA(2, "[%d -> %d:%c]", *it, runLen, c);
			for (int i=0; i<runLen; ++i)
				fprintf(f, "%c", c);
		}
		
		return m_rle.size()*sizeof(int);
	}

	void getStats(int *size, BIGNUM *em, BIGNUM *li, BIGNUM *f1, BIGNUM *f2) {
		(*size) += m_rle.size()*sizeof(int);
		
		for (Rle::iterator it = m_rle.begin(); it != m_rle.end(); ++it) {
			if (IS_EMPTY(*it))   (*em)+=GET_LEN(*it);
			if (IS_LINE(*it))    (*li)+=GET_LEN(*it);
			if (IS_FILLED(*it))  (*f1)+=GET_LEN(*it);
			if (IS_FILLED2(*it)) (*f2)+=GET_LEN(*it);
		}
	}
};

class Bitmap {
public:
	typedef vector<Row> Rows;
	Rows m_rows;
	
	void setRow(int i, Row *R) {
		while ((int)m_rows.size() <= i)
			m_rows.push_back(Row(R->m_width));
		
		m_rows[i] = *R;
		
		m_height = m_rows.size();
		m_width = R->m_width;
	}
	
	int dump(FILE *f) {
		int size=0;
		for (Rows::iterator it = m_rows.begin(); it != m_rows.end(); ++it) {
			size+=it->dump(f);
			fprintf(f, "\n");
		}
		
		return size;
	}
	
	void getStats(int *w, int *h, int *size, BIGNUM *em, BIGNUM *li, BIGNUM *f1, BIGNUM *f2) {
		*w = m_rows[0].m_width;
		*h = m_rows.size();
		
		*size=0;
		for (Rows::iterator it = m_rows.begin(); it != m_rows.end(); ++it)
			it->getStats(size, em, li, f1, f2);
	}
	
	typedef list<int> Queue;

	bool isectLines(int y1, int y2) {
		if ((y2<0) || (y2 > m_height-1))
			return false;
		
		Row::Rle::iterator it1 = m_rows[y1].m_rle.begin();
		Row::Rle::iterator it2 = m_rows[y2].m_rle.begin();
		
		int x1=0, x2=0;
		int x1end=x1+GET_LEN(*it1)-1;
		int x2end=x2+GET_LEN(*it2)-1;
		
		bool ret = false;
		
		for (; it1 != m_rows[y1].m_rle.end(); ++it1) {
			x1end=x1+GET_LEN(*it1)-1;
		
			if (IS_FILLED(*it1)) {
				// this interval is from x1 to x1end (inclusive)

				while (true) {
					bool adv=false;
					
					if (x2end < x1) {
						// nothing
						adv=true;
					}
					else 
					if (x2 <= x1end) {
						// fill, ...
						if (IS_EMPTY(*it2)) {
							MAKE_FILLED(*it2);
							DEBUGA(2, "Filling interval <%d,%d> on line %d", x2,x2end,y2);
							ret = true;
						}
						
						if (x2end >= x1end) break;
						else adv=true;
					}
					
					if (adv) {
						// advance to next interval
						x2 += GET_LEN(*it2);
						++it2;
						x2end = x2+GET_LEN(*it2)-1;
					}
				}
			}
		
			x1 += GET_LEN(*it1);
		}
		
		return ret;
	}
	
	// start fill (always from (0,0))
	void fill() {
		// it is basically a scanline floodfill over rle encoded data, using a queue instead of stack
		Queue queue;
		
		queue.push_back(0);
		MAKE_FILLED(m_rows[0].m_rle[0]);
		
		while (! queue.empty()) {
			int Y = queue.front();
			queue.pop_front();
			
			DEBUGA(2, "Processing line %d", Y);
			
			// try lines Y-1 and Y+1
			if (isectLines(Y, Y-1)) queue.push_back(Y-1);
			if (isectLines(Y, Y+1)) queue.push_back(Y+1);
		}
	}
	
private:	
	// cached image size for faster access
	int m_width, m_height;
};


class Renderer {
public:
	Renderer() : m_width(0) {}

	int getWidth() { return m_width+2; }
	int getHeight() { return m_bitmap.size()+1; }

	void clear() {
		m_width = 0;
		m_bitmap.clear();
	}

	// line drawing algorithm from problem description
	void draw_line(int x1, int y1, int x2, int y2) {
		int x_middle = (x1+x2)/2;
		int y_middle = (y1+y2)/2;

        // set_color(GREY);
        put_pixel(x_middle, y_middle);

        if((x1!=x2) || (y1!=y2))
        {
            if(abs(x1-x2) > abs(y1-y2))
            {
                if(x1<x2)
                {
                    draw_line(x1, y1, x_middle, y_middle);
                    draw_line(x_middle+1, y_middle, x2, y2);
                }
                else // x1>x2
                {
                    draw_line(x1, y1, x_middle+1, y_middle);
                    draw_line(x_middle, y_middle, x2, y2);
                }
            }
            else
            {
                if(y1<y2)
                {
                    draw_line(x1, y1, x_middle, y_middle);
                    draw_line(x_middle, y_middle+1, x2, y2);
                }
                else // y1>y2
                {
                    draw_line(x1, y1, x_middle, y_middle+1);
                    draw_line(x_middle, y_middle, x2, y2);
                }
            }
        }
    }
	
	Bitmap *createBitmap(int W, int H) {
		Bitmap *b = new Bitmap();
		Row r;
		
		for (int y=0; y<H; y++) {
			if (y%100000==0) DEBUGA(1, "Creating bitmap row %d", y);
			
			r.clear();

			if (y < (int)m_bitmap.size()) 
				r.setLinePixels(W, &m_bitmap[y]);
			else 
				r.setLinePixels(W, &m_bitmap[0]);
			
			b->setRow(y, &r);
		}
		
		return b;
	}
	
private:
	void put_pixel(int x, int y) {
		while (y >= (int)m_bitmap.size()) {
			Xcoords c;
			m_bitmap.push_back(c);
		}
		
		m_bitmap[y].insert(x);
		if (x > m_width) m_width = x;
	}
	
	Ycoords m_bitmap;
	int m_width;
};


int main(int argc, char **argv) {
	int w,h,size;
	BIGNUM em, li, f1, f2;
	int nTests, testId;

	bool doDump=false;

	if (argc>1) {
		if (!strcmp(argv[1],"--dump")) doDump=true;
	}

	Renderer RNDr;
	scanf("%d ", &nTests);
	
	for (testId=0; testId<nTests; testId++) {
		RNDr.clear();
		
		int W,H,N;
		scanf("%d %d %d ",&W, &H, &N);
		
		fprintf(stderr, "Drawing lines...\n");
		for (int i=0; i<N; i++) {
			int x1,y1,x2,y2;
			
			scanf("%d %d %d %d ", &x1,&y1,&x2,&y2);
			RNDr.draw_line(x1,y1,x2,y2);
		}
	
		fprintf(stderr, "Creating bitmap...\n");
		Bitmap *B = RNDr.createBitmap(W,H);
	
		fprintf(stderr, "Filling polygon outside...\n");
		B->fill();
		
		if (doDump) B->dump(stdout);
	
		w=h=size=0;
		em=li=f1=f2=0;
		fprintf(stderr, "Checking bitmap size...\n");
		B->getStats(&w, &h, &size, &em, &li, &f1, &f2);
	
		fprintf(stderr, "Bitmap size: %d x %d (%g MBytes), %g MBytes\n", w, h, 1.0*w*h/1024/1024, 1.0/1024/1024*size);
		fprintf(stderr, "Pixel counts: \n");
		fprintf(stderr, "  Line:    %lld\n", li);
		fprintf(stderr, "  Inside:  %lld\n", em);
		fprintf(stderr, "  Outside: %lld\n", f1);
		fprintf(stderr, "  Empty:   %lld\n", f2);

		printf("%lld %lld %lld\n", em, li, f1);
		delete B;
	}
	
    return 0;
}
