CF1401E Divide Square 题解
解题思路
其实多看几组也能发现块数等于交点的数量加上两个端点都在边上的线段数量再加一。
证明如下(图见样例):
- 对于两条只有一个端点位于边上的线段,因为保证有一个端点位于边上,那么这两条线段的交点一定会和已存在的点、边构成一个新的矩形;
- 对于其中有一条为两个端点均位于边上的两条线段,两个端点均位于边上的线段会与已存在的两边构成两个矩形;
- 剩下的不规则部分产生
的贡献。
此时问题转化为如何计算出交点数量。
考虑枚举横坐标,然后统计出此时这个坐标上有多少条横向线段,然后判断是否有一条竖线的横坐标为当前横坐标,如果有,则分以下两种情况计算:
- 存在一个端点位于 x 轴上,那么直接将答案加上纵坐标小于等于
的横线数量即可; - 其他情况,不妨设当前横坐标上有
条横向线段,那么答案应加上 减去纵坐标小于 的横线数量。
那么,我们需要做到快速维护横向线段。考虑使用树状数组。设当前横坐标为
本题步骤如下:
- 分别存储横、纵线段,横线段存两份;
- 将纵线段按
排序,两份横线段分别按 从小到大和 从大到小排序; - 枚举
,更新当前位置上的横线段数量; - 判断是否存在一条竖线段,若有则按上文所讲方法更新
即可; - 枚举每条线段,若该线段两个端点都在正方形边上,那么
; - 输出
;
注意事项
- 不开 long long 见祖宗;
- 不需要考虑树状数组越界问题;
- 先添加线段,然后计算,最后再删;
- 在计算
位于边上的线段时,一定要查询小于等于 的横线数量,而不是 。
AC 代码
#include<set>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#define int long long
#define N 100005
#define mint 0
#define maxt 1000000
int n,m;
struct Line{
int y,l,r;
}a[N],d[N];
struct lIne{
int x,l,r;
}b[N];
inline bool cmp(Line A,Line B){
return A.l<B.l;
}
inline bool Cmp(lIne A,lIne B){
return A.x<B.x;
}
inline bool CMP(Line A,Line B){
return A.r<B.r;
}
struct BitTree{
int val[(maxt<<2)+5];
#define lowbit(x) (x&(-x))
inline void Add(int x,int v){
while(x<=maxt){
val[x]+=v;
x+=lowbit(x);
}
}
inline int Query(int x){
int res=0;
while(x){
res+=val[x];
x-=lowbit(x);
}return res;
}
}tree;
signed main(){
scanf("%lld%lld",&n,&m);
for(register int i=1;i<=n;++i){
scanf("%lld",&a[i].y);
scanf("%lld",&a[i].l);
scanf("%lld",&a[i].r);
}
for(register int i=1;i<=m;++i){
scanf("%lld",&b[i].x);
scanf("%lld",&b[i].l);
scanf("%lld",&b[i].r);
}
for(register int i=1;i<=n;++i)
d[i]=a[i];
std::sort(a+1,a+n+1,cmp);
std::sort(d+1,d+n+1,CMP);
std::sort(b+1,b+m+1,Cmp);
int la=1,ra=1,lb=1,ans=0,cnt=0;
for(register int x=mint;x<=maxt;++x){
while(a[la].l==x&&la<=n){
tree.Add(a[la].y,1);
++la;++cnt;
}
if(x==b[lb].x){
if(b[lb].l==mint&&b[lb].r==maxt)
++ans;
if(b[lb].l==mint)
ans+=tree.Query(b[lb].r);
else
ans+=cnt-tree.Query(b[lb].l-1);
++lb;
}while(d[ra].r==x&&ra<=n){
tree.Add(d[ra].y,-1);
++ra;--cnt;
}
}for(register int i=1;i<=n;++i)
if(a[i].l==mint&&a[i].r==maxt)
++ans;
printf("%lld",ans+1ll);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下