hdu1255 矩阵的交(线段树+扫描线)

/*
    不是叶子节点 ,且cnt=1.注意这里,cnt=1确切的意义是什么,
    应该是,可以确定,这个区间被完全覆盖了1次,
    而有没有被完全覆盖两次或以上则不知道无法确定,那么怎么怎么办了,
    只要加上t[lch].s + t[rch].s  即,看看左右孩子区间被覆盖了一次或以上的长度,
    那么叠加在双亲上就是双亲被覆盖两次或以上的长度
*/

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 1005
struct segment
{
    double l,r,h;
    int f;
}s[maxn*2];
struct node
{
    int cnt;
    double len1;//记录一次及以上的
    double len2;//记录二次及以上的
}tree[maxn*8];
double mark[maxn<<1];
bool cmp(segment a,segment b)
{
    return a.h<b.h;
}
void build(int l,int r,int rt)
{
    tree[rt].cnt=0;
    tree[rt].len1=tree[rt].len2=0;
    if(l==r)
    {
        return ;
    }
    int m=(l+r)/2;
    build(lson);
    build(rson);
}
/*
    重点。
    若该节点的cnt >= 2,说明被至少两条线段覆盖,那么len1=len2=区间长度。
    若该节点的cnt == 1,说明该区间被一条线段覆盖,len1=区间长度,只要左右节点的len1有值,
    那么那些长度一定是至少被覆盖两次的,因此len2为左右节点的len1之和。
    若该节点的cnt = 0,说明没被完全覆盖,直接用其左右节点更新。
    还要注意特判叶子节点。
*/
void getlen(int l,int r,int rt)
{
    if(tree[rt].cnt>=2)//>=2时很好理解,就是覆盖2次或以上,直接减一减
    {
        tree[rt].len1=mark[r+1]-mark[l];
        tree[rt].len2=mark[r+1]-mark[l];
    }
    else if(tree[rt].cnt==1)//此处需要注意
                            //由于cnt大于0,所以覆盖一次或以上的部分直接得到,而由于完全覆盖一次
                            //可能其他部分有覆盖,此时就可以根据左右孩子来,由于len1记录覆盖一次或
                            //以上的,因为已经完全覆盖了一次,只要加上左右孩子的一次或以上覆盖的值
                            //那么就是2次或以上覆盖的值。
    {
        tree[rt].len1=mark[r+1]-mark[l];//因为覆盖一次,len1还要继续加
        if(l == r)//由于覆盖一次,又只有一个l==r,所以len2为0
        {
            tree[rt].len2=0;
        }
        else
        {
            tree[rt].len2=tree[rt<<1].len1+tree[rt<<1|1].len1;
        }
    }
    else if(tree[rt].cnt==0)//为完全覆盖,根据孩子来。此处与上面等于1出相似,可以发现,如果为完全覆盖
                            //就可以根据左右孩子得到覆盖的,那cnt等于1时,要求覆盖2次的时候就也可以
                            //根据孩子来。
    {
        if(l == r)
            tree[rt].len1=tree[rt].len2=0;
        else
        {
            tree[rt].len1=tree[rt<<1].len1+tree[rt<<1|1].len1;
            tree[rt].len2=tree[rt<<1].len2+tree[rt<<1|1].len2;
        }
    }
}
void updata(int L,int R,int c,int l,int r,int rt)
{
    if(l>=L&&R>=r)
    {
        tree[rt].cnt+=c;
        getlen(l,r,rt);
        return ;
    }
    int m=(l+r)/2;
    if(m>=L)
        updata(L,R,c,lson);
    if(R>m)
        updata(L,R,c,rson);
    getlen(l,r,rt);
}
int find(double val,int x,int y)
{
    int l=x,r=y,m;
    while(l<=r)
    {
        m=(l+r)/2;
        if(mark[m]==val)
            return m;
        else if(mark[m]>val)
            r=m-1;
        else l=m+1;
    }
    return -1;
}
int main()
{
    int t,n,i;
    double x1,x2,y1,y2;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        int m=0;
        for(i=0;i<n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            s[m].l=x1;s[m].r=x2;s[m].h=y1;s[m].f=1;mark[m++]=x1;
            s[m].l=x1;s[m].r=x2;s[m].h=y2;s[m].f=-1;mark[m++]=x2;
        }
        sort(s,s+m,cmp);
        sort(mark,mark+m);
        int k=1;
        for(i=1;i<m;i++)
        {
            if(mark[i]!=mark[i-1])
                mark[k++]=mark[i];
        }
        /*
        for(i=0;i<k;i++)
            printf("%.2lf ",mark[i]);
        printf("\n");
        */
        build(0,k-1,1);
        double ans=0;
        for(i=0;i<m;i++)
        {
            int ll=find(s[i].l,0,k-1);
            int rr=find(s[i].r,0,k-1)-1;
            updata(ll,rr,s[i].f,0,k-1,1);
            ans+=(s[i+1].h-s[i].h)*tree[1].len2;
        }
        printf("%.2lf\n",ans);
    }
}
时间: 2024-10-31 11:00:56

hdu1255 矩阵的交(线段树+扫描线)的相关文章

hdu1255 覆盖的面积 线段树-扫描线

矩形面积并 线段树-扫描线裸题 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<math.h> 5 using namespace std; 6 const int maxm=2e3+5; 7 const double eps=1e-5; 8 9 struct seg{ 10 double x,y1,y2; 11 int c; 12 bool operator

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 4059 Cerc2012 Non-boring sequences 线段树+扫描线

题目大意:定义一个序列为[不无聊的]当且仅当这个序列的任意一个区间都存在一个数只出现过一次,给定一个序列,要求判断这个序列是否是[不无聊的] 定义lasti表示第i个元素上一次出现的位置(第一次出现则为0),nexti表示第i个元素下一次出现的位置(最后一次出现则为n+1),那么这个元素能成为某个区间仅出现一次的数,当且仅当这个区间的左端点在[lasti+1,i]之间,右端点在[i,nexti?1]之间 我们可以将区间的左右端点放在二维平面上,那么一个元素产生的贡献是一个矩形,我们要确定的是所有

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]表示每种颜色的长

sgu316Kalevich Strikes Back(线段树+扫描线)

做法:总体想法是求出一个矩形的面积以及它所包含的矩形,然后用自己的面积减掉所包含的.主要问题是怎样求解它所包含的矩形. 因为是没有相交点的,可以利用扫描线的方法去做,类似染色,当前段如果是x色,也就是第x个矩形,那么再把他染成y颜色时,说明x包含y,而当扫到y的上边时,这一段又恢复到x色.标记一下被包含的矩形,记录所包含的矩形. 因为会有恢复染色操作,up需要时时更新,左儿子和右儿子一样颜色时就可以合并为一段. 1 ; 2 } 3 void down(int w) 4 { 5 if(s[w]!=

线段树+扫描线 HDOJ 5091 Beam Cannon

题目传送门 1 /* 2 题意:给出若干个点的坐标,用一个矩形去覆盖,问最多能覆盖几个点 3 线段树+扫描线:思路是先建一棵以[y, y + h]的树,左右儿子[x, x + w] 4 以这棵树为范围,从左到右扫描,更新点数,x的+1, x+w的-1(超过矩形范围) 5 ans = 每次更新时所覆盖点数的最大值 6 */ 7 #include <cstdio> 8 #include <algorithm> 9 #include <iostream> 10 #includ

POJ 3277 City Horizon(线段树+扫描线+离散化)

题目地址:POJ 3277 水题..稍微处理一下然后用求面积并的方法求即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <

[POI 2001+2014acm上海邀请赛]Gold Mine/Beam Cannon 线段树+扫描线

Description Byteman, one of the most deserving employee of The Goldmine of Byteland, is about to retire by the end of the year. The Goldmine management would like to reward him in acknowledgment of his conscientious work. As a reward Byteman may rece

hdu 5700区间交(线段树)

区间交 Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 849    Accepted Submission(s): 377 Problem Description 小A有一个含有n个非负整数的数列与m个区间.每个区间可以表示为li,ri. 它想选择其中k个区间, 使得这些区间的交的那些位置所对应的数的和最大. 例如样例中,选择[2,5]

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