HDU 2461 线段树扫描线

给出N个矩形,M次询问

每次询问给出R个,问这R个矩形围成的面积

经典扫面线求面积并,对每次询问的R个点离散化一下

#include "stdio.h"
#include "string.h"
#include "algorithm"
#include "map"
using namespace std;

map<int,int>mp;

struct P
{
    int x1,y1,x2,y2;
}p[21];

struct Mark
{
    int l,r,x,dir;
}mark[41];

struct node
{
    int l,r,y,s;
}data[410];

int h[50];

bool cmp(Mark a,Mark b)
{
    return a.x<b.x;
}

void callen(int k)
{
    if (data[k].s>0) data[k].y=h[data[k].r]-h[data[k].l];
    else
        data[k].y=data[k*2].y+data[k*2+1].y;
}

void build(int l,int r,int k)
{
    int mid;
    data[k].l=l;
    data[k].r=r;
    data[k].y=0;
    data[k].s=0;

    if (l+1==r) return;

    mid=(l+r)/2;

    build(l,mid,k*2);
    build(mid,r,k*2+1);
}

void updata(int l,int r,int k,int op)
{
    int mid;

    if (data[k].l==l && data[k].r==r)
    {
        data[k].s+=op;
        callen(k);
        return ;
    }

    mid=(data[k].l+data[k].r)/2;

    if (r<=mid) updata(l,r,k*2,op);
    else
        if (l>=mid) updata(l,r,k*2+1,op);
    else
    {
        updata(l,mid,k*2,op);
        updata(mid,r,k*2+1,op);
    }
    callen(k);
}

int main()
{
    int Case,cnt,i,ii,r,n,m,ans,k;
    Case=0;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        if (n==0 && m==0) break;
        for (i=1;i<=n;i++)
            scanf("%d%d%d%d",&p[i].x1,&p[i].y1,&p[i].x2,&p[i].y2);

        printf("Case %d:\n",++Case);
        for (ii=1;ii<=m;ii++)
        {
            scanf("%d",&r);
            for (i=0;i<r;i++)
            {
                scanf("%d",&k);
                mark[i*2].x=p[k].x1;
                mark[i*2].l=p[k].y1;
                mark[i*2].r=p[k].y2;
                mark[i*2].dir=1;
                mark[i*2+1].x=p[k].x2;
                mark[i*2+1].l=p[k].y1;
                mark[i*2+1].r=p[k].y2;
                mark[i*2+1].dir=-1;
                h[i*2]=p[k].y1;
                h[i*2+1]=p[k].y2;
            }

            sort(h,h+r*2);
            cnt=unique(h,h+r*2)-h;

            for (i=0;i<cnt;i++)
                mp[h[i]]=i;
            sort(mark,mark+r*2,cmp);
            for (i=0;i<r*2;i++)
            {
                mark[i].l=mp[mark[i].l];
                mark[i].r=mp[mark[i].r];
            }
            ans=0;
            build(0,cnt,1);
            updata(mark[0].l,mark[0].r,1,mark[0].dir);

            for (i=1;i<r*2;i++)
            {
                ans+=(mark[i].x-mark[i-1].x)*data[1].y;
                updata(mark[i].l,mark[i].r,1,mark[i].dir);
            }
            printf("Query %d: %d\n",ii,ans);
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-08-25 00:40:24

HDU 2461 线段树扫描线的相关文章

HDU 5107 线段树扫描线

给出N个点(x,y),每个点有一个高度h 给出M次询问,问在(x,y)范围内第k小的高度是多少,没有输出-1 (k<=10) 线段树扫描线 首先离散化Y坐标,以Y坐标建立线段树 对所有的点和询问进行离线操作,将询问和点按照x,y的大小排序,从左向右,从下向上,对于相同的(x,y)插入点在询问点之前 线段树的每个节点维护10个高度,每次询问[0,mark[i].y]的第mark[i].h高的值即可 #include "stdio.h" #include "string.h

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

http://acm.hdu.edu.cn/showproblem.php?pid=1255 典型线段树辅助扫描线,顾名思义扫描线就是相当于yy出一条直线从左到右(也可以从上到下)扫描过去,此时先将所有的横坐标和纵坐标排序 因为是从左到右扫描,那么横坐标应该离散化一下 当扫描线依次扫描的时候,依次扫描到的纵区间在线段树中查找,依据是上边还是下边记录,上边就是-1,下边就是+1, 如果某区间记录值为0的时候,代表没有被覆盖,为1的时候代表覆盖一次,为2代表覆盖两次(不会出现为负数的情况) 最后将依

hdu 1542 线段树+扫描线

啦啦啦~继续学算法 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7349    Accepted Submission(s): 3231 Problem Description There are several

HDU 5091 线段树扫描线

给出N个点,和一个w*h的矩形 给出N个点的坐标,求该矩形最多可以覆盖多少个点 对每个点point(x,y)右边生成对应的点(x+w,y)值为-1: 纵向建立线段树,从左到右扫描线扫一遍,遇到点则用该点的权值更新区间(y,y+h) #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; struct Mark { int x,y,s; }ma

HDU 1542 线段树+扫描线+离散化

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

hdu 1264 线段树+扫描线

说实话  真是水题   题目给的数据太小  都不用离散化      之前用离散化处理一个类似的题 这道题是给你几个矩形    让你求覆盖面积    重复的只算一次 做完之后被坑了        题目说输入左下角和右下角坐标    但是     左上角和右下角也有可能   只要是对角就行    所有得线处理一下 #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h>

HDU 3642 线段树+离散化+扫描线

题意:给你N个长方体的左下角和右上角坐标,问你空间中有多少体积是被大于两个不同的立方体覆盖的.x,y~10^6 z~500 考虑到给的z比较小,所以可以直接枚举z,然后跑二维的扫描线就好. 关于处理被不同的线段覆盖三次的问题,可以维护四个信息,cnt,once,twice,more,然后相互推出结果就好. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

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