HDU - 1255 扫描线+离散化进阶

这道题最开始我以为和HDU - 1542 那道题一样,只需要把cover次数改成2次即可,但是后面仔细一想,我们需要求的是覆盖次数大于等于2次的,这样的话,我们需要维护两个长度,HDU-1542 由于求的是覆盖次数大于等于一次的,我们只需要维护一个覆盖次数大于等于1的长度的len1就行,但是这道题我们要求的是覆盖两次以及两次以上的长度,这样乘以高度差,才是面积。

现在我们来想如何维护这个值?

给线段树打个标记cover,代表这个区间被完全覆盖的次数。

我们先来看看,维护覆盖一次及其以上的,应该怎么实现,我们可以从中得到启示。

  1. cover不为0 那么这个区间被完全覆盖。我们把整个区间长度给len1,但是我们由于经过离散化。表达式为:tree[root].len1=pos[r+1]-pos[l]
  2. L==R 代表跑到了叶子节点,不会有节点信息往上传,因此赋0
  3. 不满足上述两者,我们就可以认为,父节点的信息,又两个儿子节点的提供。

那么覆盖两次的呢?同样的分情况讨论

  1. cover>1 那么这个区间内被完全覆盖至少2次,值等于区间长度。
  2. L==R 同样的信息不能由子节点提供,赋0。
  3. Cover==1 那么这个区间被完全覆盖至少一,子节点覆盖次数大于等于1的次数往上pushup后,变成至少两次。
  4. 反之节点信息由两个子节点提供
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
inline int L(int r)
{
    return r<<1;
};
inline int R(int r)
{
    return r<<1|1;
};
inline int MID(int l,int r)
{
    return (l+r)>>1;
};
const int maxx = 2015;
struct Line
{
    double l,r,h;
    int f;
}line[maxx*2];
struct node
{
    int l,r,cover;
    double len1,len2;
} tree[maxx<<2];
double pos[maxx];
bool cmp(Line a,Line b){
  return a.h<b.h;
}
void buildtree(int root,int l,int r)//建树
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].len1=0;
    tree[root].len2=0;
    tree[root].cover=0;
    if (l==r)
    {
        return;
    }
    int mid = MID(l,r);
    buildtree(L(root),l,mid);
    buildtree(R(root),mid+1,r);
}
int bin(double key,int low,int high)
{
    while(low<=high)
    {
        int mid  = (low+high)>>1;
        if (pos[mid] == key)
            return mid;
        else if (pos[mid] < key)
            low = mid+1;
        else
            high = mid-1;
    }
    return -1;
}
void pushup(int root)
{
    int l=tree[root].l;
    int r=tree[root].r;
    if (tree[root].cover)tree[root].len1=pos[r+1]-pos[l];
    else if (l==r)tree[root].len1=0;
    else tree[root].len1=tree[L(root)].len1+tree[R(root)].len1;

    if (tree[root].cover>1)tree[root].len2=tree[root].len1;
    else if (l==r)tree[root].len2=0;
    else if (tree[root].cover==1)tree[root].len2=tree[L(root)].len1+tree[R(root)].len1;
    else tree[root].len2=tree[L(root)].len2+tree[R(root)].len2;
}
void update(int root,int ul,int ur,int c)
{
    int l=tree[root].l;
    int r=tree[root].r;
    if (ul<=l && r<=ur)
    {
        tree[root].cover+=c;
        pushup(root);
        return;
    }
    int mid=MID(l,r);
    if (ur<=mid)update(L(root),ul,ur,c);
    else if (ul>mid)update(R(root),ul,ur,c);
    else {
        update(L(root),ul,mid,c);
        update(R(root),mid+1,ur,c);
    }
    pushup(root);
}
int main()
{
   int t;
   scanf("%d",&t);
   int n;
   while(t--){
     int nums=0;
     scanf("%d",&n);
     for (int i=0;i<n;i++){
        double x1,x2,y1,y2;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        line[nums].l=x1;
        line[nums].r=x2;
        line[nums].h=y1;
        line[nums].f=1;
        pos[nums++]=x1;
        line[nums].l=x1;
        line[nums].r=x2;
        line[nums].h=y2;
        line[nums].f=-1;
        pos[nums++]=x2;
     }
     sort(pos,pos+nums);
     sort(line,line+nums,cmp);
     int m=1;
     for (int i=1;i<nums;i++)//去重
        if (pos[i]!=pos[i-1])
        pos[m++]=pos[i];
     buildtree(1,0,m-1);
     double ans=0;
     for (int i=0;i<nums;i++)
     {
         int l=bin(line[i].l,0,m-1);
         int r=bin(line[i].r,0,m-1)-1;
         update(1,l,r,line[i].f);
         ans+=tree[1].len2*(line[i+1].h-line[i].h);
     }
     printf("%.2lf\n",ans);
   }
   return 0;
}

原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10359046.html

时间: 2024-10-24 01:50:20

HDU - 1255 扫描线+离散化进阶的相关文章

HDU 1255 覆盖的面积 (扫描线 线段树 离散化)

题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了,因为虽然现在都不等于 2,但是之前的那个线段加上现在的已经覆盖2次了. 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include &

HDU 1255 离散化+扫描线覆盖的面积

覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3571    Accepted Submission(s): 1753 Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据

hdu 1255 覆盖的面积 线段树扫描线求重叠面积

稀里糊涂打完了没想到1A了,心情还是很舒畅的,c和c++的四舍五入还是四舍六入遇积进位遇偶舍,我感觉很混乱啊,这道题我输出的答案是7.62,也就是遇偶舍了,可是我就手动处理一下进位问题,发现0.005 系统自动进位0.01了,尼玛啊,我一下子就混乱了,不是遇偶舍么,0也是偶数啊,怎么就进位了呢.最后我就不手动处理进位问题了,直接0.2lf%,虽然我输出的结果是7.62,但是提交也过了 这道题和poj1151,hdu1542差不多,扫描线详细讲解http://blog.csdn.net/young

扫描线三巨头 hdu1928&amp;&amp;hdu 1255 &amp;&amp; hdu 1542 [POJ 1151]

学习链接:http://blog.csdn.net/lwt36/article/details/48908031 学习扫描线主要学习的是一种扫描的思想,后期可以求解很多问题. 扫描线求矩形周长并 hdu 1928 Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4795    Accepted Submission(s):

hdu 1255 覆盖的面积(扫描线)

http://acm.hdu.edu.cn/showproblem.php?pid=1255 一道挺简单的题,让我折腾了许久.主要卡在了更新节点后维护父亲节点上.后来思路明确了就很容易了. 节点信息: l,r:区间端点 cnt:区间被覆盖的次数,cnt = 0说明没有被完全覆盖. len1:区间被覆盖的长度 len2:区间至少被两条线段覆盖的长度. 只要找到父亲节点与子节点在len1,len2,cnt的关系就简单了. #include <stdio.h> #include <iostre

hdu 1255 覆盖的面积(线段树&amp;扫描线&amp;重复面积)

覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3375    Accepted Submission(s): 1645 Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数

Hdu 1255

题目链接 覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3545    Accepted Submission(s): 1739 Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每

hdu1542 Atlantis (线段树+扫描线+离散化)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9032    Accepted Submission(s): 3873 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

hdu 1255 覆盖的面积

http://acm.hdu.edu.cn/showproblem.php?pid=1255 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 100010 5 using namespace std; 6 7 int t,n; 8 double Y[maxn],X[maxn]; 9 struct point 10 { 11 double x; 12 double