矩形(离散化+树状数组)
www.cnblogs.com/shaokele/
1340: 矩形##
Time Limit: 1 Sec
Memory Limit: 128 MBDescription###
因为对polo忍无可忍, dzf使用圣剑在地上划出了许多纵横交错的沟壑来泄愤。这些沟壑都严格与X轴平行或垂直。
polo嘲笑了dzf无聊的行为,然后做了一件更加无聊的事。他蹲下来数这些沟壑的条数。数着数着,polo意识到一个问题,那就是因为圣剑的威力太大,划出的沟壑太多,地面就会塌陷。而如果两条水平的沟壑和两条垂直的沟壑相交组成了一个矩形,那么塌陷的危险就会进一步增加。现在polo已经数了n条沟壑,他想知道这些沟壑组成了多少个矩形。
Input###
第一行一个数n,接下来每行4个数x1,y1,x2,y2,表示沟壑的两个端点(x1,y1),(x2,y2)
Output###
一个数,组成的矩形个数。
Sample Input###
4
0 0 1 0
0 0 0 1
1 1 1 -1
1 1 0 1
8
1 0 4 0
2 1 2 0
0 0 0 3
2 2 2 3
3 3 3 -1
0 3 4 3
4 1 -1 1
3 2 -1 2
Sample Output
1
6
题目大意:
二位直角坐标系中有 n 条水平或竖直的线段
问能组成多少个矩形(相同方向的线段不交)
题解:
把所有的 \(y\) 坐标离散化
把所有的竖线按 \(x\) 排序
先 \(O(n)\) 枚举一条竖边,然后枚举与其相交的横边,把它的 \(y\) 坐标加入树状数组(在树状数组中的位置 \(+1\) )。预处理完毕
枚举另一条竖边,先判断是否有横边的最右端的 \(x\) 坐标已经小于当前竖边的 \(x\) 坐标,找到这条边在树状数组中的位置,删去(在树状数组中的位置 \(-1\)
然后树状数组做区间查询, \(ans\) 用数学方法累加
~~然后 \(AC\) ~~ 妈的调了这么久
(树状数组单点修改,区间查询)
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int n,num,tmp,cnt,cnt1,cnt2,L,R,mid,res,id1,id2;
ll x1,y1,x2,y2,ans,up,down;
int c[5005],to[5005];
ll a[5005];
struct node1{
ll x,l,r;
}ver[5005];
struct node2{
ll y,l,r;
}tra[5005];
bool cmp1(node1 a,node1 b){
if(a.x<b.x)return 1;
else return 0;
}
bool cmp2(node2 a,node2 b){
if(a.r<b.r)return 1;
else return 0;
}
void add(int k,int tot){
for(int i=k;i<=tmp;i+=i&(-i))
c[i]+=tot;
}
int query(int k){
int res=0;
for(int i=k;i>0;i-=i&(-i))
res+=c[i];
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
if(x1==x2){
ver[++cnt1].x=x1;
ver[cnt1].l=min(y1,y2);
ver[cnt1].r=max(y1,y2);
a[++num]=y1;
a[++num]=y2;
}
if(y1==y2){
tra[++cnt2].y=y1;
tra[cnt2].l=min(x1,x2);
tra[cnt2].r=max(x1,x2);
a[++num]=y1;
}
}
sort(ver+1,ver+cnt1+1,cmp1);
sort(tra+1,tra+cnt2+1,cmp2);
sort(a+1,a+num+1);
tmp=1;
for(int i=2;i<=num;i++)
if(a[i]!=a[i-1])
a[++tmp]=a[i];
for(int i=1;i<=cnt1;i++){
memset(c,0,sizeof(c));
memset(to,0,sizeof(to));
cnt=0;
for(int j=1;j<=cnt2;j++)
if(tra[j].l<=ver[i].x && ver[i].x<=tra[j].r && ver[i].l<=tra[j].y && tra[j].y<=ver[i].r){
res=lower_bound(a+1,a+tmp+1,tra[j].y)-a;
to[++cnt]=j;
add(res,1);
}
int p=1;
for(int j=i+1;j<=cnt1;j++){
while(p<=cnt && ver[j].x>tra[to[p]].r){
res=lower_bound(a+1,a+tmp+1,tra[to[p]].y)-a;
p++;
add(res,-1);
}
if(p>cnt)break;
up=min(ver[i].r,ver[j].r);
down=max(ver[i].l,ver[j].l);
res=lower_bound(a+1,a+tmp+1,up)-a;
id1=res;
res=lower_bound(a+1,a+tmp+1,down)-a;
id2=res;
ll tot=query(id1)-query(id2-1);
if(tot>1)ans+=tot*(tot-1)/2;
}
}
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步