题目链接:点击打开链接

A template for an artwork is a white grid of n × m squares. The artwork will be created by painting q horizontal and vertical black strokes. A stroke starts from square (x1, y1), ends at square (x2,y2)(x1=x2(x2,y2)(x1=x2 or y1=y2)y1=y2) and changes the color of all squares (x, y) to black where x1 ≤ x ≤ x2 and y1 ≤ y ≤ y2. The beauty of an artwork is the number of regions in the grid. Each region consists of one or more white squares that are connected to each other using a path of white squares in the grid, walking horizontally or vertically but not diagonally. The initial beauty of the artwork is 1. Your task is to calculate the beauty after each new stroke. Figure A.1 illustrates how the beauty of the artwork varies in Sample Input 1.


Input

The first line of input contains three integers n, m and q (1 ≤ n, m ≤ 1000, 1 ≤ q ≤ 104). Then follow q lines that describe the strokes. Each line consists of four integersx1,y1,x2x1,y1,x2 and y2(1 ≤ x1 ≤ x2 ≤ n, 1 ≤ y1 ≤ y2 ≤ m). Either x1 = x2 or y1=y2y1=y2(or both).

Output

For each of the q strokes, output a line containing the beauty of the artwork after the stroke.

Sample Input

4 6 5
2 2 2 6
1 3 4 3
2 5 3 5
4 6 4 6
1 6 4 6

Sample Output

1
3
3
4
3

题意:有一个n行m列的白色格子,现在对它采取k次涂黑操作,每次涂黑操作输入四个数,这四个数分别为起始点的x,y和终止点的x,y。要求是输出每次涂黑后,这个格子有多少个白色的联通块。

思路:反过来思考,首先将所有的涂黑操作全部涂完,使用一个结构体来记录所有的涂黑条,然后算出全部涂黑后有多少个联通块,这个是最终的联通块。

接下来对每个原先涂黑的一个个的涂白,就能依次求出倒数第一个第二个...整个图内所有的联通块。

注意:有些点涂了好几次。

#include<iostream>  
#include<cstdio>  
#include<algorithm>  
#include<cstdlib>  
#include<cstring>  
#define MAXN 5100000
using namespace std;  

struct Node{
	int numa; int numb; int numc; int numd;   
}node[11000];

int father[MAXN];  //父节点

struct HH{
	int to;  //所连接的第一个节点 
	int next;  //下一个与该节点连接的节点 
}arr[MAXN];

int ans[11000];  //答案 
int head[MAXN];  //所到达的第一个头部,会不断地更新 
int b[MAXN];  //置为1则为被抹黑 
bool visit[MAXN];   //置为1则为已经算过 
  
int m, n, k, x, y, z, sum;  
long long int ll;  

void init(int x, int y){  //构造一个节点,将x指向y 
	arr[++ll].to = y;  
	arr[ll].next = head[x];  
	head[x] = ll;    
} 

int get(int x){  //得到该节点的祖先节点 
	if(father[x] == -1) return x;  
	return father[x] = get(father[x]);   
}

void merge(int x, int y){  //合并两个节点所在的集合 
	int a = get(x);  
	int c = get(y);  
	if(a == c) return;  
	if(!visit[a] && !visit[c]) sum++; //两个这个时候都没算过
	if(visit[a] && visit[c]) sum--;  //反上 
	visit[a] = visit[c] =1;  
	father[a] = c;  
}

void Init(int x){  //将与x相连的所有点全部相连 
	for(int k=head[x]; k; k = arr[k].next){
		if(!b[arr[k].to]) merge(x,arr[k].to);  
	}
	if(!visit[x])sum++, visit[x] = 1;  
}

int main(){
	//freopen("1.txt", "r", stdin);    
	scanf("%d%d%d", &n,&m,&k);  
	for(int i=1;i<=(n+2)*(m+2);i++)  //父节点置-1 
		father[i] = -1;   
	for(int i=0;i<=m+1;i++)b[i] = 1;
	for(int i=(n+1)*(m+2); i<=(n+2)*(m+2); i++)b[i] = 1;
	for(int i=1;i<=n+2;i++){
		b[i*(m+2)-1] = 1;
	}
	for(int i=0;i<=n+2;i++){
		b[i*(m+2)] = 1;  
	}  
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			init(((m+2)*i)+j,((m+2)*i)+j+1);
			init(((m+2)*i)+j,((m+2)*i)+j-1);
			init(((m+2)*i)+j,((m+2)*(i+1)+j));
			init(((m+2)*i)+j,((m+2)*(i-1)+j));
		}
	}   
	for(int i=1; i<=k;i++){
		scanf("%d%d%d%d", &node[i].numa, &node[i].numb , &node[i].numc , &node[i].numd );  
		if(node[i].numa == node[i].numc ){
			for(int j=node[i].numb; j<=node[i].numd;j++){
				b[(m+2)*node[i].numa+j]++;  
			}
		}
		else {
			for(int j=node[i].numa;j<=node[i].numc;j++){
				b[(m+2)*j + node[i].numb]++;  
			}
		}
	}
	
	for(int i=0;i<(m+2)*(n+2);i++) {
		if(b[i] == 0) Init(i);  
	}
	
	ans[k+1] = sum;
	for(int i=k;i>=1;i--){  //对于每个划,逐个计算 
		if(node[i].numa == node[i].numc ){
			for(int j=node[i].numb; j<=node[i].numd;j++){
				b[(m+2)*node[i].numa+j]--; 
				if (!b[(m+2)*node[i].numa+j]) Init((m+2)*node[i].numa+j);
			}
		}
		else {
			for(int j=node[i].numa;j<=node[i].numc;j++){
				b[(m+2)*j + node[i].numb]--;
				if (!b[(m+2)*j + node[i].numb]) Init((m+2)*j + node[i].numb); 
			}
		}
		ans[i] = sum;  
	}
	

	for(int i=1;i<=k;i++){
		printf("%d\n", ans[i+1]);   
	}
}