http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=216#problem/W
大致题意:有一个W*H的矩形,它的左下角是(0,0),右上角是(W,H),在这个大的矩形内有n个小矩形,这n个小矩形可以包含但不能相交,n个小矩形把W*H的大矩形分成n+1块,按从小到大的顺序输出每一块面积。
首先先计算出每个矩形的面积,对于每一块的面积,我们只需知道这个矩形所包含的矩形,然后减去它所包含的矩形的面积,就是这一块的面积。我们用线段树维护一段线段上被哪个矩形覆盖,当遍历到一条边时,我们只需查询这条边被覆盖的信息,就知道它的前驱了,它们之间建一条边。
对矩形的横坐标进行离散化,建立一棵线段树,节点增加一个信息col,表示这一段被哪一条线段覆盖。
每个矩形产生两条线段,线段节点增加一个信息tag,标志着这条线段是哪一条线段以及是下边还是上边。对线段按y排序后,从下往上开始扫描,对于当前的线段,在线段树中查找其对应的前驱,即它所在外面矩形的下边,它们之间建一条有向边。
最后dfs分别减去一个矩形内所包含的矩形。
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
#define C 240
#define S 20
using namespace std;
const int maxn = 120010;
struct node
{
int l,r;
int col;
}tree[maxn*4];
struct Line
{
int x1,x2,y,tag;
bool operator < (const struct Line &tmp)const
{
return y < tmp.y;
}
}line[maxn];
LL s[60010];
int x[maxn],cnt;
int pre[maxn];
vector <int> edge[maxn];
int Binsearch(int l, int r, int key)
{
int low = l;
int high = r;
while(high >= low)
{
int mid = (low + high) >> 1;
if(x[mid] == key)
return mid;
if(x[mid] > key)
high = mid-1;
else low = mid+1;
}
return -1;
}
void push_down(int v)
{
if(tree[v].l == tree[v].r)
return;
if(tree[v].col != -1)
{
tree[v*2].col = tree[v*2+1].col = tree[v].col;
tree[v].col = -1;
}
}
void build(int v,int l,int r)
{
tree[v].l = l;
tree[v].r = r;
tree[v].col = 0;
if(l == r)
return;
int mid = (l+r)>>1;
build(v*2,l,mid);
build(v*2+1,mid+1,r);
}
//询问[l,r]所在区间的被覆盖的是哪条线段,那么这条线段就是当前线段的前驱
int query(int v, int l, int r)
{
if(tree[v].col != -1)
return tree[v].col;
int mid = (tree[v].l + tree[v].r) >> 1;
if(r <= mid)
return query(v*2,l,r);
else if(l > mid)
return query(v*2+1,l,r);
else
return query(v*2,l,mid);
}
void update(int v, int l, int r, int tag)
{
if(tree[v].l == l && tree[v].r == r)
{
if(tag > 0)
tree[v].col = tag;
else tree[v].col = pre[-tag]; //重点理解,这条边是上边,要把对应的区间置为它下边的前驱
return;
}
push_down(v);
int mid = (tree[v].l + tree[v].r) >> 1;
if(r <= mid)
update(v*2,l,r,tag);
else if(l > mid)
update(v*2+1,l,r,tag);
else
{
update(v*2,l,mid,tag);
update(v*2+1,mid+1,r,tag);
}
}
//根据建立的边减去每个矩形所包含的矩形
void dfs(int u)
{
for(int i = 0; i < (int)edge[u].size(); i++)
{
int v = edge[u][i];
s[u] -= s[v];
dfs(v);
}
}
int main()
{
int n,W,H,x1,x2,y1,y2;
scanf("%d %d %d",&n,&W,&H);
s[0] = (LL)W*H;
cnt = 0;
memset(pre,0,sizeof(pre));
for(int i = 1; i <= n; i++)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
if(x1 > x2)
swap(x1,x2);
if(y1 > y2)
swap(y1,y2);
line[++cnt] = (struct Line){x1,x2,y1,i};
x[cnt] = x1;
line[++cnt] = (struct Line){x1,x2,y2,-i};
x[cnt] = x2;
s[i] = (LL)(x2-x1)*(y2-y1);
}
sort(x+1,x+1+cnt);
int k = 1;
for(int i = 2; i <= cnt; i++)
{
if(x[i] != x[k])
x[++k] = x[i];
}
cnt = k;
build(1,1,cnt);
sort(line+1,line+1+n*2);
for(int i = 1; i <= n*2; i++)
{
int l = Binsearch(1,cnt,line[i].x1);
int r = Binsearch(1,cnt,line[i].x2)-1;
if(line[i].tag > 0)
{
pre[line[i].tag] = query(1,l,r);
edge[pre[line[i].tag]].push_back(line[i].tag);
}
update(1,l,r,line[i].tag);
}
dfs(0);
sort(s,s+n+1);
for(int i = 0; i <= n; i++)
{
printf("%lld",s[i]);
if(i == n) printf("\n");
else printf(" ");
}
return 0;
}