bzoj 1818: [Cqoi2010]内部白点 (扫描线+线段树)
来源:互联网 发布:php 极客学院 编辑:程序博客网 时间:2024/04/28 14:42
题目描述
传送门
题目大意:无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1 < y < y2使得(x,y1)和(x,y2)都是黑点)。
题解
将坐标离散化,对于每一行维护存在黑点的最靠左/右的列,左端+1的位置权值+1,右端的位置权值-1
然后我们找出同列的相邻两个黑点的区间。
从左到右依次扫描每一列,将所有的在该列以及之前的操作都加入到线段树中,然后查询当前列区间的权值,计入答案即可。
代码
#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>#define N 500003#define LL long long using namespace std;struct data{ int opt,x,l,r,val;}q[N];struct node{ int x,y;}a[N];int n,x[N],y[N],dx[N],dy[N],L[N],R[N],st[N],cnt;LL tr[N*4];int cmp(node a,node b){ return a.y<b.y||a.y==b.y&&a.x<b.x;}int cmp1(data a,data b){ return a.x<b.x||a.x==b.x&&a.opt<b.opt;}void update(int now){ tr[now]=tr[now<<1]+tr[now<<1|1];}void pointchange(int now,int l,int r,int x,LL val){ if (l==r) { tr[now]+=val; return; } int mid=(l+r)/2; if (x<=mid) pointchange(now<<1,l,mid,x,val); else pointchange(now<<1|1,mid+1,r,x,val); update(now);}LL query(int now,int l,int r,int ll,int rr){ if (ll>rr) return 0; if (ll<=l&&r<=rr) return tr[now]; int mid=(l+r)/2; LL ans=0; if (ll<=mid) ans+=query(now<<1,l,mid,ll,rr); if (rr>mid) ans+=query(now<<1|1,mid+1,r,ll,rr); return ans;}int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d%d",&a[i].x,&a[i].y); dx[++cnt]=a[i].x; dy[cnt]=a[i].y; dx[++cnt]=a[i].x-1; dy[cnt]=a[i].y-1; dx[++cnt]=a[i].x+1; dy[cnt]=a[i].y+1; } sort(dx+1,dx+cnt+1); sort(dy+1,dy+cnt+1); int cx=unique(dx+1,dx+cnt+1)-dx-1; int cy=unique(dy+1,dy+cnt+1)-dy-1; for (int i=1;i<=n;i++) a[i].x=lower_bound(dx+1,dx+cx+1,a[i].x)-dx, a[i].y=lower_bound(dy+1,dy+cy+1,a[i].y)-dy; for (int i=1;i<=cx;i++) L[i]=cy+1; for (int i=1;i<=n;i++) L[a[i].x]=min(L[a[i].x],a[i].y),R[a[i].x]=max(R[a[i].x],a[i].y); sort(a+1,a+n+1,cmp); cnt=0; for (int i=1;i<=cx;i++) if (L[i]!=cy+1&&L[i]!=R[i]){ ++cnt; q[cnt].opt=1; q[cnt].x=L[i]+1; q[cnt].l=i; q[cnt].val=1; ++cnt; q[cnt].opt=1; q[cnt].x=R[i]; q[cnt].l=i; q[cnt].val=-1; } int l=1; for (int i=1;i<=cy;i++) { int t1=0; while (a[l].y==i&&l<=n) { st[++t1]=a[l].x; l++; } for (int j=2;j<=t1;j++) { ++cnt; q[cnt].opt=2; q[cnt].x=i; q[cnt].l=st[j-1]+1; q[cnt].r=st[j]-1; } } sort(q+1,q+cnt+1,cmp1); LL ans=n; l=1; for (int i=1;i<=cy;i++) { while (q[l].x<=i&&l<=cnt) { if (q[l].opt==1) pointchange(1,1,cx,q[l].l,q[l].val); else ans+=query(1,1,cx,q[l].l,q[l].r); l++; } } printf("%lld\n",ans);}
0 0
- bzoj 1818: [Cqoi2010]内部白点 (扫描线+线段树)
- [BZOJ1818][Cqoi2010]内部白点(扫描线+线段树)
- [BZOJ 1818] CQOI2010 内部白点
- BZOJ 1818 [Cqoi2010]内部白点
- BZOJ1818 [Cqoi2010]内部白点 扫描线/线段求交
- BZOJ 1818 Cqoi2010 内部白点 树状数组
- 1818: [Cqoi2010]内部白点
- 1818: [Cqoi2010]内部白点
- 【bzoj1818】[Cqoi2010]内部白点
- 【bzoj1818】[Cqoi2010]内部白点
- [BZOJ1818] [Cqoi2010]内部白点
- bzoj1818[Cqoi2010]内部白点
- 【bzoj1818】[Cqoi2010]内部白点
- bzoj1818: [Cqoi2010]内部白点
- bzoj1818: [Cqoi2010]内部白点
- 【bzoj1818】 CQOI2010内部白点 树状数组计数
- BZOJ 1818 线段树+扫描线
- BZOJ1818: [Cqoi2010]内部白点 树状数组+离散化
- 砝码称重I
- dubbo配置文件解析
- std::bind的使用
- 设计模式-桥接模式
- 快速排序算法-Java、Python实现
- bzoj 1818: [Cqoi2010]内部白点 (扫描线+线段树)
- op补偿以及容性负载如何应对
- 砝码称重II
- 程序员日常工作英文记录
- NYOJ 1248 海岛争霸 河南省赛真题 Floyd 或者 并查集
- AI的春天?
- 素数圆环-dfs
- ubuntu16.04LTS安装搜狗输入法
- 2017年 4月24日