题目大意:
注释代码:
/*
* Problem ID : POJ 3832 Posters
* Author : Lirx.t.Una
* Language : G++
* Run Time : 500 ms
* Run Memory : 8500 KB
*/
#pragma G++ optimize("O2")
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
//海报的最大数量
#define MAXPOSN 50000
//横坐标的最大值
#define MAXCORD 50000
//线段树的根结点指针
#define ROOT 1
//底边bottom为1,定边top为-1
#define BTOM 1
#define TOP -1
//求树tree的左右子树(都是指针值)
#define LFT(TREE) ( (TREE) << 1 )
#define RHT(TREE) ( LFT(TREE) | 1 )
using namespace std;
typedef __int64 llg;//最后面积可能会超出int值
struct Scan {//扫描线,和x轴平行
int x1, x2;//左右端点
int y;//高度
char v;//类型,也为值value,即botm还是top
bool
operator<(const Scan &oth)
const {//对扫描线按照从低到高排序,尽量将底边排在前面
if ( y == oth.y ) return v > oth.v;
return y < oth.y;
}
};
//以下两个数组构成虚线段树
//共同维护一个线段树的两个域
//由于只取每个结点所代表线段的长度因此不需要记录
//结点所代表的线段的左右区间端点
int val[MAXPOSN * 4];//每个结点的重叠值
int len[MAXPOSN * 4];//每个结点的长度
Scan scn[MAXPOSN * 8];//扫描线,每个回字都分为上下左右四块
//因此一个回字最多有8条横向扫描线
int m;//扫描线的条数
int max_cord, min_cord;//找出所有扫描线中的最左端点和最右端点
//以这两个值作为根结点线段的左右端点,可以有效降低线段树的规模,并
//降低二分次数(即时间复杂度)
void
add( int x1, int x2, int y, int v ) {//添加扫描线
scn[m].x1 = x1;
scn[m].x2 = x2;
scn[m].y = y;
scn[m].v = (char)v;
m++;
}
void
chg_mx( int x1, int x2 ) {//对max_cord, min_cord进行跟新
if ( x1 < min_cord ) min_cord = x1;
if ( x2 > max_cord ) max_cord = x2;
}
void
cal_len( int tree, int lft, int rht ) {//calculate length
//计算tree结点所代表线段的长度
//传统算法
//lft和rht为tree结点所代表的线段的区间
if ( val[tree] ) len[tree] = rht - lft;
else
if ( 1 + lft == rht ) len[tree] = 0;
else len[tree] = len[ LFT(tree) ] + len[ RHT(tree) ];
}
void
update( int tree, int lft, int rht, int al, int ar, int av ) {//传统的线段树update
//只不过结点的区间由传参lft和rht指定
//而跟新区间为adding lft和adding rht,即al和ar
//跟新进来的扫描线的类型为adding value,即av
if ( lft == al && ar == rht ) {
val[tree] += av;
cal_len( tree, lft, rht );
return ;
}
int mid;
mid = ( lft + rht ) >> 1;
if ( ar <= mid ) update( LFT(tree), lft, mid, al, ar, av );
else if ( al >= mid ) update( RHT(tree), mid, rht, al, ar, av );
else {
update( LFT(tree), lft, mid, al, mid, av );
update( RHT(tree), mid, rht, mid, ar, av );
}
cal_len( tree, lft, rht );
}
int
main() {
int n;//回字的个数
int x1, y1;//外左下角
int x2, y2;//外右上角
int x3, y3;//内左下角
int x4, y4;//内右上角
int i;//计数变量
llg ans;//最终阴影部分面积
while ( scanf("%d", &n), n ) {
//初始化
m = 0;
memset(val, 0, sizeof(val));
memset(len, 0, sizeof(len));
max_cord = -1;
min_cord = MAXCORD + 1;
while ( n-- ) {
scanf("%d%d%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
if ( x1 != x3 ) {//空心是否和左边重合
add( x1, x3, y1, BTOM );
add( x1, x3, y2, TOP );
chg_mx( x1, x3 );
}
if ( x4 != x2 ) {//空心是否和右边重合
add( x4, x2, y1, BTOM );
add( x4, x2, y2, TOP );
chg_mx( x4, x2 );
}
if ( y1 != y3 ) {//空心是否和下边重合
add( x3, x4, y1, BTOM );
add( x3, x4, y3, TOP );
}
if ( y4 != y2 ) {//空心是否和上边重合
add( x3, x4, y4, BTOM );
add( x3, x4, y2, TOP );
}
chg_mx( x3, x4 );//对于上下两种情况只要计算一次即可
}
sort(scn, scn + m);//从低到高排序
ans = 0;
i = 0;
while ( i < m ) {
do {
update( ROOT, min_cord, max_cord, scn[i].x1, scn[i].x2, scn[i].v );
i++;
} while ( i < m && scn[i].y == scn[i - 1].y );//先将同一高度的扫描线update
if ( i < m )//累加一次面积
ans += (llg)len[ROOT] * (llg)( scn[i].y - scn[i - 1].y );
}
printf("%I64d\n", ans);
}
return 0;
}
无注释代码:
#pragma G++ optimize("O2")
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define MAXPOSN 50000
#define MAXCORD 50000
#define ROOT 1
#define BTOM 1
#define TOP -1
#define LFT(TREE) ( (TREE) << 1 )
#define RHT(TREE) ( LFT(TREE) | 1 )
using namespace std;
typedef __int64 llg;
struct Scan {
int x1, x2;
int y;
char v;
bool
operator<(const Scan &oth)
const {
if ( y == oth.y ) return v > oth.v;
return y < oth.y;
}
};
int val[MAXPOSN * 4];
int len[MAXPOSN * 4];
Scan scn[MAXPOSN * 8];
int m;
int max_cord, min_cord;
void
add( int x1, int x2, int y, int v ) {
scn[m].x1 = x1;
scn[m].x2 = x2;
scn[m].y = y;
scn[m].v = (char)v;
m++;
}
void
chg_mx( int x1, int x2 ) {
if ( x1 < min_cord ) min_cord = x1;
if ( x2 > max_cord ) max_cord = x2;
}
void
cal_len( int tree, int lft, int rht ) {
if ( val[tree] ) len[tree] = rht - lft;
else
if ( 1 + lft == rht ) len[tree] = 0;
else len[tree] = len[ LFT(tree) ] + len[ RHT(tree) ];
}
void
update( int tree, int lft, int rht, int al, int ar, int av ) {
if ( lft == al && ar == rht ) {
val[tree] += av;
cal_len( tree, lft, rht );
return ;
}
int mid;
mid = ( lft + rht ) >> 1;
if ( ar <= mid ) update( LFT(tree), lft, mid, al, ar, av );
else if ( al >= mid ) update( RHT(tree), mid, rht, al, ar, av );
else {
update( LFT(tree), lft, mid, al, mid, av );
update( RHT(tree), mid, rht, mid, ar, av );
}
cal_len( tree, lft, rht );
}
int
main() {
int n;
int x1, y1;
int x2, y2;
int x3, y3;
int x4, y4;
int i;
llg ans;
while ( scanf("%d", &n), n ) {
m = 0;
memset(val, 0, sizeof(val));
memset(len, 0, sizeof(len));
max_cord = -1;
min_cord = MAXCORD + 1;
while ( n-- ) {
scanf("%d%d%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4);
if ( x1 != x3 ) {
add( x1, x3, y1, BTOM );
add( x1, x3, y2, TOP );
chg_mx( x1, x3 );
}
if ( x4 != x2 ) {
add( x4, x2, y1, BTOM );
add( x4, x2, y2, TOP );
chg_mx( x4, x2 );
}
if ( y1 != y3 ) {
add( x3, x4, y1, BTOM );
add( x3, x4, y3, TOP );
}
if ( y4 != y2 ) {
add( x3, x4, y4, BTOM );
add( x3, x4, y2, TOP );
}
chg_mx( x3, x4 );
}
sort(scn, scn + m);
ans = 0;
i = 0;
while ( i < m ) {
do {
update( ROOT, min_cord, max_cord, scn[i].x1, scn[i].x2, scn[i].v );
i++;
} while ( i < m && scn[i].y == scn[i - 1].y );
if ( i < m )
ans += (llg)len[ROOT] * (llg)( scn[i].y - scn[i - 1].y );
}
printf("%I64d\n", ans);
}
return 0;
}
单词解释: