HDU 3642 Get The Treasury (线段树扫描线)

题意:给你一些长方体,问你覆盖三次及以上的体积有多大

首先我们观察x轴y轴一样很大,但是z轴很小,所以我们可以枚举z轴(-500,500),注意我们枚举的是每一段长度为一的z轴的xy轴的面积而不是点。接着就是求在这一段内的矩形面积并的变形

注意我们要首先计算,再插入线段求面积并

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<string>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define eps 1E-8
/*注意可能会有输出-0.000*/
#define Sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
#define Cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
#define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
#define mul(a,b) (a<<b)
#define dir(a,b) (a>>b)
typedef long long ll;
typedef unsigned long long ull;
const int Inf=1<<28;
const double Pi=acos(-1.0);
const int Mod=1e9+7;
const int Max=1010;
struct node
{
    int xx1,yy1,zz1,xx2,yy2,zz2;
} rec [Max];
struct nude
{
    int xx1,xx2,yy1,cover;
} lin[Max<<1];
struct nide
{
    int cover,dp[4];//覆盖次数 此点代表值
} segtr[Max<<3];
map<int,int> mp;
int mpx[Max<<1];
void Upnow(int now,int next)
{
    segtr[now].dp[0]=segtr[next].dp[0]+segtr[next|1].dp[0];
    return;
}
void Create(int sta,int enn,int now)
{
    segtr[now].dp[1]=segtr[now].dp[2]=segtr[now].dp[3]=0;
    segtr[now].cover=0;
    if(sta==enn)
    {
        segtr[now].dp[0]=mpx[sta+1]-mpx[sta];
        return;
    }
    int mid=dir(sta+enn,1);
    int next=mul(now,1);
    Create(sta,mid,next);
    Create(mid+1,enn,next|1);
    Upnow(now,next);
    return;
}
void Jud(int sta,int enn,int now)
{
    int next=mul(now,1);
    if(segtr[now].cover>=3)
    {
        segtr[now].dp[3]=segtr[now].dp[0];
        segtr[now].dp[1]=segtr[now].dp[2]=0;
    }
    else if(segtr[now].cover==2)
    {
        segtr[now].dp[1]=0;
        if(sta==enn)
        {
            segtr[now].dp[3]=0;
        }
        else
        {
            segtr[now].dp[3]=segtr[next].dp[1]+segtr[next|1].dp[1]+segtr[next].dp[2]+segtr[next|1].dp[2]+segtr[next].dp[3]+segtr[next|1].dp[3];
        }
         segtr[now].dp[2]=segtr[now].dp[0]-segtr[now].dp[3];
    }
    else if(segtr[now].cover==1)
    {
    if(sta==enn)
    {
        segtr[now].dp[2]=segtr[now].dp[3]=0;
        segtr[now].dp[1]=segtr[now].dp[0];
    }
    else
    {
        segtr[now].dp[2]=segtr[next].dp[1]+segtr[next|1].dp[1];
        segtr[now].dp[3]=segtr[next].dp[2]+segtr[next|1].dp[2]+segtr[next].dp[3]+segtr[next|1].dp[3];
        segtr[now].dp[1]=segtr[now].dp[0]-segtr[now].dp[3]-segtr[now].dp[2];
    }
    }
    else
    {
          if(sta==enn)
     {
        segtr[now].dp[1]=segtr[now].dp[2]=segtr[now].dp[3]=0;
    }
    else
    {
        segtr[now].dp[1]=segtr[next].dp[1]+segtr[next|1].dp[1];
        segtr[now].dp[2]=segtr[next].dp[2]+segtr[next|1].dp[2];
        segtr[now].dp[3]=segtr[next].dp[3]+segtr[next|1].dp[3];
    }
    }
    return;
}
void Update(int sta,int enn,int now,int x,int y,int z)
{
    if(x<=sta&&enn<=y)
    {
        segtr[now].cover+=z;
        Jud(sta,enn,now);
        return;
    }
    int mid=dir(sta+enn,1);
    int next=mul(now,1);
    if(mid>=x)
        Update(sta,mid,next,x,y,z);
    if(mid<y)
        Update(mid+1,enn,next|1,x,y,z);
    Jud(sta,enn,now);
    return;
}
bool cmp(struct nude p1,struct nude p2)
{
    if(p1.yy1==p2.yy1)
        return p1.cover>p2.cover;
    return p1.yy1<p2.yy1;
}
ll Vol(int n,int cnt,int coun)//求z轴在区间内的面积三次及以上并
{
    if(!coun)
        return 0ll;
    ll sum=0ll;
    Create(1,cnt,1);//按照x轴建树
    sort(lin,lin+coun,cmp);//按照y轴排序后枚举线段
    Update(1,cnt,1,mp[lin[0].xx1],mp[lin[0].xx2]-1,lin[0].cover);//第一条线段不能加到总面积上
    for(int i=1; i<coun; ++i) //按照y轴枚举每条线
    {
        sum+=(ll)segtr[1].dp[3]*(lin[i].yy1-lin[i-1].yy1);//一定更新到了父节点   注意先计算
        Update(1,cnt,1,mp[lin[i].xx1],mp[lin[i].xx2]-1,lin[i].cover);
    }
    return sum;
}
ll Solve(int n)
{
    ll sum=0ll;
    for(int i=0; i<1000; ++i) //枚举所有可能的z轴
    {
        mp.clear();
        int coun=0;
        for(int j=0; j<n; ++j)
        {
            if(rec[j].zz1<=i&&rec[j].zz2>i)//段变点
            {
                mp[rec[j].xx1]=1;
                mp[rec[j].xx2]=1;
                lin[coun].xx1=rec[j].xx1,lin[coun].xx2=rec[j].xx2,lin[coun].yy1=rec[j].yy1,lin[coun++].cover=1;
                lin[coun].xx1=rec[j].xx1,lin[coun].xx2=rec[j].xx2,lin[coun].yy1=rec[j].yy2,lin[coun++].cover=-1;
            }
        }
        int cnt=0;
        for(map<int,int>::iterator it=mp.begin(); it!=mp.end(); ++it)
        {
            it->second=++cnt;//离散化
            mpx[cnt]=it->first;
        }
        mpx[cnt+1]=mpx[cnt];
        sum+=Vol(n,cnt,coun);
    }
    return sum;
}
int main()
{
    int t,n,coun=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; ++i)
        {
            scanf("%d %d %d %d %d %d",&rec[i].xx1,&rec[i].yy1,&rec[i].zz1,&rec[i].xx2,&rec[i].yy2,&rec[i].zz2);
            rec[i].zz1+=500,rec[i].zz2+=500;
        }
        printf("Case %d: %I64d\n",++coun,Solve(n));
    }
    return 0;
}
时间: 2024-10-10 14:44:51

HDU 3642 Get The Treasury (线段树扫描线)的相关文章

HDU 3642 Get The Treasury 线段树+扫描线

反向标记是错的,要对矩形进行拆分 #include <cstdio> #include <algorithm> #include <cstring> #include <vector> typedef long long LL; using namespace std; #define lson rt << 1,l,mid #define rson rt << 1 | 1,mid + 1,r const int maxn = 5e4

hdu 3642 Get The Treasury (三维的扫描线)

题目大意: 给出N个立方体. 求一个三维空间中被包围三次的空间的体积之和. 思路分析: 发现Z的范围很小.那么我们可以枚举Z轴,然后对 x y做扫描线. 而且不用枚举所有的Z ,只需要将Z离散化之后枚举. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define maxn 2222 #define debug puts("fuck!&q

HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)

Problem A : Counting Squares From:HDU, 1264 Problem Description Your input is a series of rectangles, one per line. Each rectangle is specified as two points(X,Y) that specify the opposite corners of a rectangle. All coordinates will be integers in t

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 覆盖的面积 线段树扫描线求重叠面积

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

HDU 4419 Colourful Rectangle --离散化+线段树扫描线

题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何维护每种颜色的长度着实让我伤透了脑筋.后来看了一位朋友的题解,才幡然醒悟. 开始想到了用二进制表示颜色,R用001表示,G用010表示,B用100表示.那么就可以用十进制1~7表示7种不同颜色了. 维护 cov[rt][1~3] 表示此区间内3种原色各有多少个, Len[rt][i]表示每种颜色的长

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255 题意很清楚,就是让你求矩阵之间叠加层数大于1的矩形块的面积和. 因为n只有1000,所以我离散化一下,数据大小就缩小了,那么之后只需要线段树单点更新就好了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <map> 5 #include <algor

杭电 HDU ACM 1225 Atlantis (线段树 扫描线 离散化 最基本)

acm第一发扫描线问题,其实算法原理很好理解 ,但是具体实现起来还是遇到诸多问题,我尝试参考了网上两份对于解决 线段树表示区间问题的方法, 第一种是每个结点的真实值,比如对于更新离散化后的1 ~ 4区间,我们在线段树中更新的是1 ~ 3,这样单个结点也可以表示一个最小单位区间. 第二种那就是在建树的时候改变通常策略,1 ~ 10 为总区间,两个孩子为1 ~ 5 ,5 ~ 10. 核心难点:当我们每次找到需要更新的区间,首先应该更新cover值,然后判断此时是被覆盖了,还是解除覆盖了,如果刚好被覆

HDU 1255 覆盖的面积 线段树+扫描线

同 POJ1151 这次是两次 #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <stack> #include <queue> #include <cmath> #include <vector

hdu 5091 Beam Cannon(线段树+扫描线+离散化)

Beam Cannon Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 457    Accepted Submission(s): 175 Problem Description Recently, the γ galaxies broke out Star Wars. Each planet is warring for resou