HDU 1542 Atlantis 线段树矩形并 看别人的题解看了好多遍啊。 还是用了好久时间排错。

http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html

用的是此博文所说的方法。。也参考了他的代码。。真的是排错排的好辛苦啊。。

。。下次把周长并的也做掉好了。。


 /*
  *以前一直云里雾理的Atantic,今天终于要自己动手写啦!!
  *@author ipqhjjybj
  *@data 20130626
  */


#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

#include <iostream>
#include <cmath>
#include <algorithm>
#include <numeric>
#include <utility>

#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <string>
using namespace std;

#define inf 0x3f3f3f3f
#define MAXN 1000
#define clr(x,k) memset((x),(k),sizeof(x))
#define cpy(x,k) memcpy((x),(k),sizeof(x))
#define Base 10000

typedef vector<int> vi;
typedef stack<int> si;
typedef vector<string> vs;
#define sz(a) int((a).size())
#define pb push_back
#define all(c) (c).begin(),(c).end()
#define rep(i,n) for(int i = 0;i < n;++i)
#define foreach(it,c) for(vi::iterator it = (c).begin();it != (c).end();++it)

#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
struct Line{
    double y_down,y_up;
    double x;
    int flag; // flag=1表示左边,flag=2表示右边
    bool operator<(const Line &a) const{
        return (x<a.x);
    }
}lines[250];
double yy[250],ty[250];
int tot,tyNum,yNum;
struct Tree{
    int l,r;
    int cover;
    double c; //表示跨度
}tree[2000];
void Build(int left,int right,int rt){
    tree[rt].l=left;
    tree[rt].r=right;
    tree[rt].c = 0.0;
    tree[rt].cover=0;
    if(left+1==right)      //一条线段需要2个点。。不用接着往下建拉!!
        return;
    int mid=(left+right)>>1;
    Build(left,mid,rt<<1);
    Build(mid,right,rt<<1|1);
}
void fun(int i){
    if(tree[i].cover)
         tree[i].c=yy[tree[i].r]-yy[tree[i].l]; //如果cover大于1,那么整段都可用于与下一线段求并面积
     else if(tree[i].l+1==tree[i].r) //叶子线段
         tree[i].c=0;
     else
         tree[i].c=tree[2*i].c+tree[2*i+1].c; //很简单的dp
}
void Delete(int left,int right,int rt){
    if(tree[rt].l>right||tree[rt].r<left)return;
    if(tree[rt].l>=left && tree[rt].r<=right){
        tree[rt].cover--;
        fun(rt);
        return;
    }
    Delete(left,right,rt<<1);
    Delete(left,right,rt<<1|1);
    fun(rt);
}
void Insert(int left,int right,int rt){
    if(tree[rt].l>right||tree[rt].r<left)return;

    if(tree[rt].l>=left && tree[rt].r<=right){
        tree[rt].cover++;
        fun(rt);
        return;
    }
    Insert(left,right,rt<<1);
    Insert(left,right,rt<<1|1);
    //tree[rt].c = tree[rt<<1].c+tree[rt<<1|1].c;
    fun(rt);
}

int CorresFind(int left,int right,double y){
    int mid = (left+right)>>1;
    if(left==right)return left;
    if(yy[mid]==y)return mid;
    else if(yy[mid] > y)
        return CorresFind(left,mid-1,y);
    else return CorresFind(mid+1,right,y);
}

int main(){
    //freopen("1542.in","r",stdin);
    int n;
    double x1,y1,x2,y2;
    int tt=0;
    while(scanf("%d",&n)&& n){
        yNum=tyNum=tot = 0;
        for(int i = 0;i < n;i++){
            scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);

            lines[tot].y_down=y1,lines[tot].y_up=y2,lines[tot].x=x1,lines[tot].flag=1,tot++;
            lines[tot].y_down=y1,lines[tot].y_up=y2,lines[tot].x=x2,lines[tot].flag=2,tot++;
            ty[tyNum++]=y1;ty[tyNum++]=y2;
        }
        sort(ty,ty+2*n);
        sort(lines,lines+2*n);


        yy[++yNum]=ty[0];
        for(int i= 1;i < tyNum;i++)
            if(ty[i]!=ty[i-1])
                yy[++yNum]=ty[i];
        //yy从1到yNum
        Build(1,yNum,1);

        int l1,l2;
        double ans=0.0;
        for(int i=0;i<tot-1;i++){

            l1 = CorresFind(1,yNum,lines[i].y_down);
            l2 = CorresFind(1,yNum,lines[i].y_up);
            if(lines[i].flag==1)
                Insert(l1,l2,1);
            else Delete(l1,l2,1);
            ans+=tree[1].c*(lines[i+1].x-lines[i].x);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++tt,ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值