首页 > 其他分享 >【BZOJ1818】【CQOI2010】【XSY2428】内部白点(树状数组+扫描线)

【BZOJ1818】【CQOI2010】【XSY2428】内部白点(树状数组+扫描线)

时间:2022-10-28 18:46:37浏览次数:53  
标签:XSY2428 扫描线 树状 int 数组 端点 BZOJ1818 竖线

先把所有点的\(x\)坐标离散化。

然后分别将所有点按\(x\)、\(y\)排序。这里以按\(x\)排序为例,对于\(x\)坐标相同的两个点,我们把它们连成一条线段。那么按\(y\)坐标排序也一样,把\(y\)坐标相同的两个点也连成一条线段。

那么连出来后的图就是这样的:

在这里插入图片描述

那么横竖线段的所有交点(图中蓝点)即为可以变dark的点,因为它左右有dark点,上下都有dark点,符合变dark条件。

那么我们怎么维护交点呢?我们考虑用扫描线(如图黑线)。

我们先把横线、竖线的两个端点全部塞进一个数组里,然后把它们按\(y\)坐标排序。

然后从\(y\)坐标的小到大一个一个向上扫描,分3种情况讨论:

  1. 如果扫描到一条竖线的下端点\((x,y)\),那么我们把树状数组里的位置\(x\)加\(1\),即\(add(x,1)\)。

  2. 如果扫描到一条竖线的上端点\((x,y)\),那么我们把树状数组里的位置\(x\)减\(1\),即\(add(x,-1)\)。那么对于某一条竖线\(l\),其上端点为\((x,y_1)\),下端点为\((x,y_2)\),我们就能保证当扫描线在区间\([y_1,y_2]\)时树状数组中位置\(x\)会\(+1\)。

  3. 如果扫描到一条横线,且两端点横坐标为\(x_1\)、\(x_2\)(\(x_1<x_2\)),我们只要查询\(query(x_2)-query(x_1-1)\)就可以得到这条线段上与其它竖线的交点坐标了,不过由于竖线与横线两端点的交点不能算进去,所以应该查询\(query(x_2-1)-query(x_1)\)。

那么最后答案就是所有交点的个数了。

代码如下:

#include<bits/stdc++.h>
 
#define N 100010
 
using namespace std;
 
struct Point
{
    int x,y;
}p[N];
 
struct Line 
{
    int opt,x,r,y;//1 竖线下端点 0 横线 -1 竖线上端点
}l[N*10];
 
int n,ans,cnt,b[N],c[N];
 
 //树状数组
int lowbit(int x)
{
    return x&-x;
}
 
void add(int x,int y)
{
    for(;x<=n;x+=lowbit(x))c[x]+=y;
}
 
int query(int x)
{
    int ans=0;
    for(;x;x-=lowbit(x))ans+=c[x];
    return ans;
}
 
bool cmpx(Point a,Point b){return a.x==b.x?a.y<b.y:a.x<b.x;}
bool cmpy(Point a,Point b){return a.y==b.y?a.x<b.x:a.y<b.y;}
bool cmpLine(Line a,Line b){return a.y==b.y?a.opt<b.opt:a.y<b.y;}
 
void work()
{
    sort(p+1,p+n+1,cmpx);
    for(int i=1;i<n;i++)
    {
        if(p[i].x==p[i+1].x)
        {
            l[++cnt]=(Line){1,p[i].x,0,p[i].y};
            l[++cnt]=(Line){-1,p[i].x,0,p[i+1].y};
        }
    }
    sort(p+1,p+n+1,cmpy);
    for(int i=1;i<n;i++)
        if(p[i].y==p[i+1].y)
            l[++cnt]=(Line){0,p[i].x,p[i+1].x,p[i].y};
}
 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&p[i].x,&p[i].y);
        b[i]=p[i].x;
    }   
    sort(b+1,b+n+1);//离散化
    int tot=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++)
        p[i].x=lower_bound(b+1,b+tot+1,p[i].x)-b;
  	work();//加入线段
    sort(l+1,l+cnt+1,cmpLine);//扫描
    for(int i=1;i<=cnt;i++)
    {
        if(!l[i].opt)ans+=query(l[i].r-1)-query(l[i].x);
        else add(l[i].x,l[i].opt);
    }
    printf("%d\n",ans+n);
    return 0;
}

标签:XSY2428,扫描线,树状,int,数组,端点,BZOJ1818,竖线
From: https://www.cnblogs.com/ez-lcw/p/16837098.html

相关文章

  • 扫描线
    P5816[CQOI2010]内部白点//结论:最多进行一次变色过程//推论:不会输出-1证明:反证//本题做法:扫描线//只计算横坐标相同,纵坐标相邻//与纵坐标相......
  • 【综合笔试题】难度 4.5/5,扫描线的特殊运用(详尽答疑)
    ​题目描述这是LeetCode上的218.天际线问题,难度为困难。Tag:「扫描线问题」、「优先队列(堆)」城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给......
  • uva688 (扫描线)
    AmobilephonecompanyACMICPC(AdvancedCellular,Mobile,andInternet-ConnectedPhoneCorporation)isplanningtosetupacollectionofantennasformobileph......
  • AcWing 算法提高课 线段树+扫描线法 求矩形之并的面积
    例题:求解多个长方形之并的面积https://www.acwing.com/problem/content/249/蓝色表示长方形,红色表示扫描线如下图所示,对于每一个横向的区间,在纵向维护线段树根据纵向......
  • 矩形面积并(扫描线)
      思路:扫描线的思路很容易确定,但难点在于如何实现。这里避免写持久化标记,最初的想法是记录区间内0的个数(即未覆盖点的个数),但是如此一来每一次更新都需要将tag下放到最......
  • 浅谈扫描线
    准备学习扫描线的时候,发现洛谷日报上并没有关于扫描线的文章,于是心血来潮想写一篇。顺便纪念一下我马上结束的OI生涯。前置知识线段树或树状数组(不会的请【模板】线......
  • 扫描线
    1离线2支持单点查询3单点维护操作顺序及其他信息从而维护历史信息(数据结构基于操作这一维)4对操作进行差分扫描时扫到改点时留存的操作就是位于该点的操作5可对数据结......
  • 扫描线
    扫描线的一些经典应用:求n个矩形的面积并和周长并。面积并(P5490【模板】扫描线)首先扫描线的思想就是假设有一条无限长度的线从一个方向到另一个方向扫一遍整个图形,这样......
  • 模拟赛 d (扫描线,三维偏序,线段树合并,并查集,线段树上二分)
    PRO题目大意:给定$N$个矩形,求连通块个数。($1\leqN,x_1,x_2,y-1,y_2\leq100000$)SOL乍一看就能知道是扫描线,不过这题的细节恐怖的要命。(std同样看不懂,自己魔改了一......
  • 【学习笔记/模板】扫描线 周长并
    先开坑,晚上再写。P1856[IOI1998][USACO5.5]矩形周长PictureCode#include<cstdio>#include<algorithm>usingnamespacestd;constintMAXN=1e5+10;intn,......