poj 1151 亚特兰蒂斯

来源:互联网 发布:win7 网络 0对象 编辑:程序博客网 时间:2024/04/29 17:16

第一次接触线段树,感觉确实很复杂,看了很久

一些关于线段树的介绍http://dongxicheng.org/structure/segment-tree/

主要参考了这个解题报告

线段树结构中,每个节点所表示的key值含义是一个很重要的东西,如何赋予它具体的含义,以及更新和查询,

感觉是一个重点问题

下面这个是转的http://blog.sina.com.cn/s/blog_77dc9e0801018v2z.html

#include <cstdio>#include <iostream>#include <cstring>#include <cstdlib>using namespace std;                                              //////#define INF 20000000#define MAX 10010#define max(a,b)(a>b?a:b)///int n;double x1, x2, y1, y2;int num;double y[MAX];struct Line{    double x, y1, y2;    int flag;}lline[MAX];struct node{    int left, right;    double l, r, len;    int flag;}pt[MAX];int cmp1(const void *a, const void *b){    if(*(double *)a > *(double *)b) return 1;    else return -1;}int cmp2(const void *a, const void *b){        if( (*(Line *)a).x > (*(Line *)b).x ) return 1;    else return -1;}  void buildTree(int l, int r, int pos){    pt[pos].left = l, pt[pos].right = r;    pt[pos].l = y[l], pt[pos].r = y[r];    pt[pos].len = pt[pos].flag = 0;        if( (l+1) == r ) return ;    int mid = (l+r)/2;    buildTree(l, mid, pos*2);    buildTree(mid, r, pos*2+1);}void insertLength(int pos){    if(pt[pos].flag > 0)        pt[pos].len = (pt[pos].r - pt[pos].l);    else if( (pt[pos].left+1) == pt[pos].right )        pt[pos].len = 0;    else        pt[pos].len = (pt[pos*2].len + pt[pos*2+1].len);} void insert(Line e, int pos){    if(pt[pos].l == e.y1 && pt[pos].r == e.y2)    {        pt[pos].flag += e.flag;        insertLength(pos);        return ;    }        if(e.y1 >= pt[pos*2 + 1].l)        insert(e, pos*2 + 1);    else if(e.y2 <= pt[pos * 2].r)        insert(e, pos * 2);    else    {        Line temp = e;        temp.y2 = pt[pos * 2].r;        insert(temp, pos * 2);                temp = e;        temp.y1 = pt[pos * 2 + 1].l;        insert(temp, pos * 2 + 1);    }    insertLength(pos);}int main(){freopen("F:\\input.txt","r",stdin );///int i, j;int caseNum = 1;while (scanf("%d", &n) != EOF){if (n == 0)break;num = 1;for (i = 0; i < n; i++){scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);lline[num].x = x1;lline[num].y1 = y1;lline[num].y2 = y2;lline[num].flag = 1;y[num++] = y1;lline[num].x = x2;lline[num].y1 = y1;lline[num].y2 = y2;lline[num].flag = -1;y[num++] = y2; }qsort(y + 1, num - 1, sizeof(y[1]), cmp1);        qsort(lline + 1, num - 1, sizeof(lline[1]), cmp2);buildTree(1, num - 1, 1);insert(lline[1], 1);double result = 0;        for(i = 2; i < num; ++i)        {            result += pt[1].len * (lline[i].x - lline[i - 1].x);             insert(lline[i], 1);        }        printf("Test case #%d\n",caseNum++);        printf("Total explored area: %.2f\n\n",result);   //printf("\n");}///    return 0;}                                              


模仿写了一个,采用指针的方式

注意sort的参数值是左闭区间,右开区间

 对于Y坐标进行区间处理建立“基于Y坐标的”线段树

注意:线段树除了最后一层外,每一层都是满的,也即是说要么是叶子,要么两个孩子都有

线段树结构中的key值是要根据具体问题来设定,比如

本题中:len表示:当前区间下有效y长度的值,每一次插入垂直于x的线段以后,更新该值,

树根的含义则为,当前情况下总区间内有效区间长度,该长度乘以【下一个线段x坐标 - 当前线段x坐标】即为该段x坐标下

距离,依次向右推进,逐步计算,得出所有的面积。不会出现重复计算,因为每次插入都更新了叶子结点中

有效长度的情况,int flag就是为了来表示当前叶子的有效长度的标记,如果为正那么当前长度有效。

之前像用bool flag来表示,无法通过,还是按照叠加值来表示

#include <iostream>#include <sstream>#include <cstdio>#include <cstring>#include <cmath>#include <string>#include <vector>#include <set>#include <cctype>#include <algorithm>#include <cmath>#include <deque>#include <queue>#include <map>#include <queue>#include <list>#include <iomanip>using namespace std;                                               //////#define maxn 1005double x1pos, y1pos, x2pos, y2pos;//线段树的结点结构struct Node{double ld, rd;//左右区间标记Node *lc, *rc;//左右孩子double len;//该区间的有效长度int flag;//标记重复Node(){ld = rd = 0;lc = rc = NULL;len = 0;flag = 0;}}Segment_tree[maxn];struct Line{double x, y_1, y_2;int flag;Line(){x = y_1 = y_2 = 0;flag = 0;}}lines[maxn];bool operator < (Line l1, Line l2){return l1.x < l2.x;}double ypos[maxn];//暂存y坐标int n;Node *buildtree(int a,int b){     Node * p = new Node;//给P申请一块内存     p->ld = ypos[a];     p->rd = ypos[b]; p->len = 0;    //{初始化 p->key }     if(abs(a - b) == 1){p->lc = p->rc = NULL;return p;//叶子节点 }    p->lc = buildtree(a, (a + b)/2);     p->rc = buildtree((a + b)/2, b);     return p; } void update(Node *node){if (node->flag > 0)node->len = node->rd - node->ld;else if (node->lc == NULL && node->rc == NULL)node->len = 0;elsenode->len = node->lc->len + node->rc->len;}void insert_sg_tree(Node *T, Line edge){int i, j;//如果相等刚好覆盖区间if (edge.y_1 == T->ld && edge.y_2 == T->rd){T->flag += edge.flag;update(T);return;}//如果小于左子区间if (edge.y_2 <= T->lc->rd)insert_sg_tree(T->lc, edge);//如果大于右子区间边界else if (edge.y_1 >= T->rc->ld)insert_sg_tree(T->rc, edge);else{Line tempLine;tempLine = edge;tempLine.y_2 = T->lc->rd;insert_sg_tree(T->lc, tempLine);tempLine = edge;tempLine.y_1 = T->rc->ld;insert_sg_tree(T->rc, tempLine);}update(T);}int main(){///int i, j, k;int cases = 1;while (scanf("%d", &n) != EOF){if (n == 0)break;int num = 0;for (i = 0; i < n; i++){scanf("%lf %lf %lf %lf", &x1pos, &y1pos, &x2pos, &y2pos);lines[num].x = x1pos;lines[num].y_1 = y1pos;lines[num].y_2 = y2pos;lines[num].flag = 1;ypos[num++] = y1pos;lines[num].x = x2pos;lines[num].y_1 = y1pos;lines[num].y_2 = y2pos;lines[num].flag = -1;ypos[num++] = y2pos;}//对y坐标进行排序sort(ypos, ypos + num);//对即将插入的直线数组进行排序sort(lines, lines + num);//对于y坐标构建区间树Node *Tree = NULL;Tree = buildtree(0, num - 1);//每插入一次垂直于x轴的线段,更新当前线段树中的len关键数值double ans = 0;insert_sg_tree(Tree, lines[0]);for (i = 1; i < num; i++){ans += Tree->len * (lines[i].x - lines[i - 1].x);insert_sg_tree(Tree, lines[i]);}printf("Test case #%d\n", cases++);printf("Total explored area: %.2f\n", ans);printf("\n");}///    return 0;}                                              

原创粉丝点击