世事还是如此无常,关键是要有平常心!
http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html
详细耐心的解说,包您一看就懂,假一罚十!
以下是poj1177求多个矩形边缘周长的代码以及注释:
吐槽:WA了很久很久,原因是因为什么呢? maxn定义得太小了。
人家的坐标是 [-10000,10000],即使离散化,应该也有很多个点。
对于我容易错的地方:
R > m 要递归右子树
maxn
离散化的时候 开始的指针为1
//attention:
//将线段树看成一个线段,它的每个点的意义是包括它本身的单位向后为一的线段
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define lson l,m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define maxn 22222
using namespace std;
//分别表示该区间的左端点、右端点表示的线段的右端点是否被覆盖
bool lbd[maxn << 2],rbd[maxn << 2];
int len[maxn << 2];//表示该节点区间所覆盖的长度
int cnt[maxn << 2],numseg[maxn << 2];//分别表示该区间有几条线段覆盖、从远处看有几条线段
struct Seg{
int l , r , h , s;
Seg() {}
Seg(int a,int b,int c,int d):l(a) , r(b) , h(c) , s(d) {}
bool operator < (const Seg &cmp) const {
if (h == cmp.h) return s > cmp.s;
return h < cmp.h;
}
}seg[maxn << 1];
void push_up(int rt, int l, int r){
if(cnt[rt]){
lbd[rt] = rbd[rt] = true;
len[rt] = r - l + 1;
numseg[rt] = 2;
}else if(l == r){
len[rt] = numseg[rt] = lbd[rt] = rbd[rt] = 0;
}else{
lbd[rt] = lbd[rt << 1]; rbd[rt] = rbd[rt << 1 | 1];
len[rt] = len[rt << 1] + len[rt << 1 | 1];
numseg[rt] = numseg[rt << 1] + numseg[rt << 1 | 1];
if(lbd[rt << 1 | 1] && rbd[rt << 1]) numseg[rt] -= 2;
}
}
void update(int L, int R, int c, int l ,int r, int rt){
if(L <= l && r <= R){
cnt[rt] += c;
push_up(rt,l,r); return ;
}
int m = (l + r) >> 1;
if(L <= m) update(L,R,c,lson);
if(R > m) update(L,R,c,rson);
push_up(rt,l,r);
}
int main(){
int n,a,b,c,d,s;
int ret;
while(scanf("%d",&n)!= EOF){
s = 0; ret = 0;
int lt = 1000000, rt = - 100000;
memset(len,0,sizeof(len));
memset(numseg,0,sizeof(numseg));
memset(cnt,0,sizeof(cnt));
memset(lbd,0,sizeof(lbd));
memset(rbd,0,sizeof(rbd));
for(int i = 0; i < n; i ++){
scanf("%d%d%d%d",&a,&b,&c,&d);
lt = min(lt,a);
rt = max(rt,c);
//1表示矩形的下边
seg[s ++] = Seg(a,c,b,1);
//-1表示矩形的上边。
//我是从下往上扫描,所以遇到下边即插入,遇到上边即删除
//由update里面的cnt[rt] += c 反应
seg[s ++] = Seg(a,c,d,-1);
}
sort(seg,seg+ s); //排序保证从下往上扫描
int last = 0; seg[s] .h = 0;
for(int i = 0; i < s ; i ++){
if(seg[i].l <seg[i].r)
//正因为线段树的定义,这里才插入的是 r - 1
update(seg[i].l,seg[i].r - 1,seg[i].s,lt,rt,1);
ret += abs(len[1] - last); //差值
ret += numseg[1] * (seg[i + 1].h - seg[i].h); //线段数 * 统计区间长度
last = len[1];
}
printf("%d\n",ret);
}
return 0;
}
int bin(int low, int high, double key,double X[]){
while(low < high){
int mid = (low + high) >> 1;
if(X[mid] < key) low = mid + 1;
else high = mid;
}
return low;
}