线段树 1828(扫描+离散化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828

具体看 http://www.cnblogs.com/shuaiwhu/archive/2012/04/22/2464876.html 的讲解

我一开始连讲解都听不懂  直接看代码才慢慢明白的

看了一遍他的代码 自己手打了一遍  所以几乎一样~

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAX 5010
#define ABS(X) ((X)>=0?(X):(-(X)))
using namespace std;
struct node
{
    int x, y1, y2, flag;
}scan[MAX<<1];

int y[MAX<<1];
struct Tree
{
    int l, r, cnt, line, lbd, rbd, sum;
}tree[MAX<<4];
int cmp1( const void *a, const void *b )
{
    node *c = (node *)a ;
    node *d = (node *)b ;
    if( c->x == d->x )
        return c->flag <= d->flag ?1:-1;   //先处理输入再处理输出,两条竖线重叠时才不计算ans内
else return c->x >= d->x ?1:-1; } int cmp2( const void *a, const void *b ) { return *(int *)a >= *(int *)b ?1: -1; } void build( int l, int r, int pos ) { tree[pos].l = l, tree[pos].r = r; tree[pos].cnt = tree[pos].line = tree[pos].lbd = tree[pos].rbd =tree[pos].sum = 0; if( l + 1 == r ) //叶节点不需要再分 再中分就再跳不出去
return ; else { int mid = (tree[pos].l + tree[pos].r)/2 ; build( l, mid, pos*2 ); build(mid, r, pos*2+1 ); } } void update_sum( int pos ) { if(tree[pos].cnt > 0) tree[pos].sum = y[tree[pos].r] - y[tree[pos].l]; // else if( tree[pos].l == tree[pos].r ) // return ; else { tree[pos].sum = tree[pos*2].sum + tree[pos*2+1].sum ; } } void update_line( int pos ) { if( tree[pos].cnt > 0 ) { tree[pos].lbd = tree[pos].rbd = 1; tree[pos].line = 1; } else { tree[pos].lbd = tree[pos*2].lbd; tree[pos].rbd = tree[pos*2+1].rbd; //注意两个子节点连续的情况,即tree[pos*2].rbd=tree[pos*2+1].lbd=1
tree[pos].line
= tree[pos*2].line + tree[pos*2+1].line - rbd*tree[pos*2+1].lbd ;

} }
void update( int l, int r, int pos, int mark ) { int mid = (tree[pos].l + tree[pos].r)/2 ; if( y[tree[pos].l] == l && y[tree[pos].r] == r ) //y储存的是真正的纵坐标, tree[pos].l,tree[pos].r储存的只是映射的
mark
== 1 ?tree[pos].cnt ++ : tree[pos].cnt --; else if( tree[pos].l + 1 == tree[pos].r ) //是叶节点且不是匹配的l r直接返回 不update_sum,update_line。 注意这里else if 的意思 是前面两个条件缺一不可
return ; else if( r <= y[mid] ) update(l, r, pos*2, mark); else if( l >= y[mid] ) update(l, r, pos*2+1,mark); else { update(l, y[mid], pos*2, mark); update(y[mid], r, pos*2+1, mark); } update_sum( pos ); update_line( pos ); } int main() { int i, x1, y1, x2, y2, n, ans; while( scanf("%d", &n) !=EOF ) { ans = 0, i = -1; while( n-- ) { scanf("%d %d %d %d", &x1, &y1, &x2, &y2); scan[++i].x = x1; scan[i].y1 = y1; scan[i].y2 = y2; scan[i].flag = 1; y[i+1] = y1; scan[++i].x = x2; scan[i].y1 = y1; scan[i].y2 = y2; scan[i].flag = 0; y[i+1] = y2; } int count = i+1; qsort( scan, count, sizeof(scan[0]), cmp1 ); qsort( y+1, count, sizeof(y[1]), cmp2 ); int unique_cnt = unique( y+1, y+1+count ) - y - 1; //unique 所有的纵坐标
build(
1, unique_cnt, 1 ); int pre_sum, pre_line ; for( int j=0; j<count; j++ ) { update( scan[j].y1, scan[j].y2, 1, scan[j].flag ); if(j >= 1) { ans += 2*pre_line*( scan[j].x - scan[j-1].x ); ans += ABS(tree[1].sum - pre_sum); //跟之前的对比!!很巧妙!!
}
else ans += tree[1].sum ; pre_sum = tree[1].sum ; pre_line = tree[1].line ; } printf("%d\n", ans); } return 0; }

 

 

posted @ 2013-01-05 23:47  April_Tsui  阅读(197)  评论(0编辑  收藏  举报