2156 矩形中的线段

平面上有n条线段。共m次询问,每次询问给出一个边平行于坐标轴的矩形,问 每条与矩形有交的线段与矩形的交的长度之和 与 所有线段的长度之和 的 比值,要求输出与标准答案的差的绝对值不超过

线段以的形式给出,表示以为端点的线段,保证任意两条线段没有交点或重合部分,且

矩形以的形式给出,表示矩形,保证

输入

第一行一个整数n
接下来n行,每行四个由空格分隔的整数x1,y1,x2,y2,表示线段
接下来一行一个整数m
接下来m行,每行四个由空格分隔的整数x1,y1,x2,y2,表示询问的矩形

输出

对每个询问,输出一行,一个介于0和1之间的十进制小数,表示答案

输入样例

2
1 1 4 4
2 1 4 3
4
1 1 6 6
1 1 3 3
2 1 3 3
1 2 2 4

输出样例

1
0.6
0.4
0

解析:

将线段按斜率正负分类,不失一般性这里只考虑斜率为正数的线段,并将每个询问矩形转化为四个形如{(x,y)|x≤x0,y≤y0}的区域的查询。由于斜率为正,线段和查询区域的边界至多只有一个端点,此时线段和查询区域有4种位置关系:(1)被完全包含,(2)完全在区域外,(3)和射线{(x,y0)|x<x0}有交,(4)和射线{(x0,y)|y≤y0}有交。情况(1)可以把线段视为点转化为查询区域内点权和,情况(2)对答案无影响,情况(3)和(4)类似,因此只需讨论(4)。使用扫描线,令扫描线平行于y轴,沿x轴正方向移动,使用平衡树维护扫描线上的线段的相对顺序,情况(4)相当于在平衡树上查询y前缀的信息。线段被分为两类,每个询问被拆成了4个区域,(1)(3)(4)3种贡献,因此每个询问被拆成24个子问题,常数较大。时间复杂度O((n+m)logn),空间复杂度O(n+m)。

放代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double ld;
#define mp make_pair
#define PI pair<int,int>
#define poly vector<ll>
#define For(i,l,r) for(int i=(int)(l);i<=(int)(r);i++)
#define Rep(i,r,l) for(int i=(int)(r);i>=(int)(l);i--)
#define pb push_back
#define fi first
#define se second
inline char gc(){static char buf[100000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline ll read(){ll x = 0; char ch = gc(); bool positive = 1;for (; !isdigit(ch); ch = gc())    if (ch == '-')  positive = 0;for (; isdigit(ch); ch = gc())   x = x * 10 + ch - '0';return positive ? x : -x;
}
inline void write(ll a){if(a<0){a=-a; putchar('-');}if(a>=10)write(a/10);putchar('0'+a%10);
}
inline void writeln(ll a){write(a); puts("");}
inline void wri(ll a){write(a); putchar(' ');}
inline ull rnd(){return ((ull)rand()<<30^rand())<<4|rand()%4;
}
#define lowbit(i) i&-i
const int N=100005,M=1000005;
struct line{int a,b,c,d;
}key[N];
ld sumlen,len[N],yx[N],yy[N],ans[N<<1];
int X,FG,qq,zt[N];
PI fg[N<<1];
pair<int,PI> q[N<<2];
ld getlen(line a){return sqrt((ll)(a.c-a.a)*(a.c-a.a)+(ll)(a.d-a.b)*(a.d-a.b));
}
struct d2{ld a,b;
};
d2 operator +(d2 a,d2 b){return (d2){a.a+b.a,a.b+b.b};
}
d2 operator -(d2 a,d2 b){return (d2){a.a-b.a,a.b-b.b};
}
void operator +=(d2 &a,d2 b){a=a+b;
}
struct d4{d2 a,b;
}ze;
d4 operator +(d4 a,d4 b){return (d4){a.a+b.a,a.b+b.b};
}
d4 operator -(d4 a,d4 b){return (d4){a.a-b.a,a.b-b.b};
}
struct segd2{d2 c[M+1];void ins(int pos,d2 x){for(int i=pos;i<=M;i+=lowbit(i))c[i]+=x;}d2 ask(int pos){d2 ans=(d2){0,0};for(int i=pos;i;i-=lowbit(i))ans+=c[i];return ans;}
}T1,T2;
ld Get(line a){return (ld)(X-a.a)/(a.c-a.a)*(a.d-a.b)+a.b;
}
bool CMP(line a,int k){return (ll)(X-a.a)*(a.d-a.b)<=(ll)(k-a.b)*(a.c-a.a);
}
bool cmp(line a,line b){return Get(a)>=Get(b);
}
struct SPLAY{int rt,fa[N],ch[N][2];d4 s[N],v[N];void print(){cout<<"debug"<<endl;cout<<rt<<endl;cout<<"end"<<endl;}inline int get(int x){return ch[fa[x]][1]==x;}inline void update(int x){s[x]=s[ch[x][0]]+s[ch[x][1]]+v[x];}void rotate(int x){int f=fa[x],g=fa[f],c=get(x);fa[x]=g; if(g)ch[g][get(f)]=x;ch[f][c]=ch[x][c^1]; fa[ch[f][c]]=f;ch[x][c^1]=f; fa[f]=x;update(f); update(x);}void splay(int x){for(;fa[x];rotate(x))if(fa[fa[x]])rotate(get(x)==get(fa[x])?fa[x]:x);rt=x;}void ins(int &x,int id){if(!x){x=id; splay(x); return;}if(cmp(key[id],key[x])){if(!ch[x][1])fa[id]=x;ins(ch[x][1],id);} else{if(!ch[x][0])fa[id]=x; ins(ch[x][0],id);}}void era(int x){splay(x); if(!ch[x][0]){fa[ch[x][1]]=0; rt=ch[x][1]; ch[x][1]=0; return;}int t=ch[x][0];fa[t]=0;while(ch[t][1])t=ch[t][1];splay(t); ch[t][1]=ch[x][1]; fa[ch[t][1]]=t; update(t); ch[x][0]=ch[x][1]=0;}d4 ask(int x,int k){if(!x)return ze;if(CMP(key[x],k)){return ask(ch[x][1],k)+s[ch[x][0]]+v[x]; }else return ask(ch[x][0],k);}void ins(int x,d4 y){v[x]=y; ins(rt,x);}pair<d4,d4> ask(int k){update(rt); d4 a=ask(rt,k),b=s[rt]-a; return mp(a,b);}
}S1,S2;
int main(){int n=read();For(i,1,n){key[i].a=read();key[i].b=read();key[i].c=read();key[i].d=read();if(key[i].a>key[i].c){swap(key[i].a,key[i].c);swap(key[i].b,key[i].d);}fg[++FG]=mp(key[i].a,i);fg[++FG]=mp(key[i].c,-i);zt[i]=key[i].b>key[i].d;len[i]=getlen(key[i]);yx[i]=len[i]/abs(key[i].c-key[i].a); yy[i]=len[i]/abs(key[i].d-key[i].b);sumlen+=len[i];}int m=read();For(i,1,m){int x1=read(),y1=read(),x2=read(),y2=read();q[++qq]=mp(x1,mp(y1,i));q[++qq]=mp(x2,mp(y1,i+m));q[++qq]=mp(x1,mp(y2,i+m));q[++qq]=mp(x2,mp(y2,i));}sort(&q[1],&q[qq+1]);sort(&fg[1],&fg[FG+1]);int dq=1;For(o,1,qq){while(fg[dq].fi<=q[o].fi&&dq<=FG){X=fg[dq].fi;int j=abs(fg[dq].se);if(fg[dq].se>0){if(zt[j]){ld A=-yy[j],B=key[j].b*yy[j];T2.ins(key[j].b,(d2){A,B});d4 jb; jb.a.a=yx[j]; jb.a.b=0; jb.b.a=yy[j]; jb.b.b=len[j]-(yx[j]*key[j].c+yy[j]*key[j].b);S1.ins(j,jb);}else{ld A=-yy[j],B=key[j].b*yy[j];T2.ins(1,(d2){A,B});T2.ins(key[j].b,(d2){-A,-B});d4 jb; jb.a.a=yx[j]; jb.a.b=-yx[j]*key[j].a; jb.b.a=yy[j]; jb.b.b=-key[j].b*yy[j];S2.ins(j,jb);}}else{if(zt[j]){ld A=yy[j],B=-key[j].b*yy[j];T2.ins(key[j].b,(d2){A,B});S1.era(j);} else {ld A=yy[j],B=-key[j].b*yy[j];T2.ins(1,(d2){A,B});T2.ins(key[j].b,(d2){-A,-B});S2.era(j);}int AA=min(key[j].b,key[j].d),BB=max(key[j].b,key[j].d);T1.ins(AA,(d2){yy[j],-yy[j]*AA});T1.ins(BB,(d2){-yy[j],len[j]+yy[j]*AA});         }dq++;}PI j=q[o].se; X=q[o].fi;pair<d4,d4> z1=S1.ask(j.fi),z2=S2.ask(j.fi);d2 dy=T1.ask(j.fi),dx=z1.fi.a+z2.fi.a;dy+=T2.ask(j.fi); dy+=z1.fi.b+z2.se.b;ld sum=dy.a*j.fi+dx.a*X+dy.b+dx.b;ans[j.se]+=sum;}For(i,1,m)printf("%.10lf\n",(double)fabs((ans[i]-ans[i+m])/sumlen));
}

51nod2156 矩形中的线段相关推荐

  1. 平面中判断线段与矩形是否相交

    文章目录 1. 原理 2. 实现 3. 参考 1. 原理 这个问题的算法思路挺简单的.分成两步来判断: 判断线段的两个端点是否在矩形内,如果两个端点至少有一个在矩形内,说明线段与矩形相交. 如果两个端 ...

  2. WinAPI: PtInRect - 判断点是否在矩形中

    为什么80%的码农都做不了架构师?>>>    本例效果图: unit Unit1;interfaceusesWindows, Messages, SysUtils, Variant ...

  3. MapXtreme 2005学习(3):向图层中添加线段

    向图层中添加线段和向图层中添加点是一样的,其本质都是向图层中添加一个图元,只是属于不同类型的图元.并且点和线段是可以在一个图存上共存的.代码示例如下: /// <summary>     ...

  4. python判断点在矩形内_Python测试点是否在矩形中

    我是python的新手,仍然学习绳索??,但是我希望有更多经验的人可以帮助我. 我正在尝试编写以下Python脚本: >创造四个点 >创建四个矩形 >检查每个点是否在任何矩形中,然后 ...

  5. Java黑皮书课后题第3章:**3.23(几何:点是否在矩形内)编写程序,提示用户输入点(x,y),然后检测该点是否在以原点为中心、宽为10、高为5的矩形中

    @TOC,然后检测该点是否在以原点为中心.宽为10.高为5的矩形中) 题目 题目概述 **3.23(几何:点是否在矩形内)编写程序,提示用户输入点(x,y),然后检测该点是否在以原点为中心.宽为10. ...

  6. Java黑皮书课后题第3章:3.16(随机点)编写程序,显示矩形中一个随机点的坐标。矩形中心位于(0,0),宽100高200

    3.16(随机点)编写程序,显示矩形中一个随机点的坐标.矩形中心位于(0,0),宽100高200 题目 题目描述 破题 代码 题目 题目描述 3.16(随机点)编写程序,显示矩形中一个随即点的坐标.矩 ...

  7. java矩形翻转_如何判断一个点在旋转后的矩形中

    前言 最近在做的一款游戏中,用到点与旋转矩形的判定来获得一个选中的物体.在此做个记录 如图所示,黄色的颜料屏是旋转的,如果不做处理直接判断点是否在矩形中,那么点击红点的位置会判定为选中物体.显然这是不 ...

  8. 序列划分c语言,看懂了这些,你对缠论中的线段划分就基本掌握了!

    原标题:看懂了这些,你对缠论中的线段划分就基本掌握了! 我也没有那菩萨心肠去救苦救难,解救广大散户与水深火热之中,那也不是我的职责所在,更不是我的义务!救了他们,谁来救我呢?他们不亏钱,我又去赚谁的钱 ...

  9. 应用区域生长(Seeded Region Growing)算法提取2D激光中的线段数据

    0 Background 本文是针对于 **<A line segment extraction algorithm using laser data based on seeded regio ...

最新文章

  1. 瀑布式开发与敏捷开发的区别是什么
  2. Android笔记——四大组件详解与总结
  3. [C] 跨平台使用Intrinsic函数范例1——使用SSE、AVX指令集 处理 单精度浮点数组求和(支持vc、gcc,兼容Windows、Linux、Mac)...
  4. C#计算一段程序运行时间的三种方法
  5. 聊一聊ws2_32.dll和wsock32.dll
  6. C和指针之字符串之strlen、strcpy、 strcat、strcmp使用总结
  7. 小程序底部弹窗css_微信小程序之animation底部弹窗动画(两种方法)
  8. 原创 | 灵魂拷问:Java对象的内存分配过程是如何保证线程安全的?
  9. Typora+PicGo-Core(command line)+SMMS、github、gitee实现Typora图片上传到图床
  10. 谈FTP服务器***技术及其展望 (下)
  11. python颜色过渡
  12. Win7 vs2010+Silverlight4开发安装顺序
  13. 免费https ssl证书freessl.org的申请及配置
  14. MacOS 开发 - isFlipped(坐标系)
  15. Java如何判断字符串中包含有全角,半角符号
  16. Android向服务器发送图片(一)
  17. centos系统 yum 安装php-redis扩展
  18. 研究生联系导师需要注意什么
  19. 【Basic Use Case】
  20. Linux--装好之后要做的几件事(转)

热门文章

  1. 常见的几种服务器代理
  2. Presto on Apache Kafka 在 Uber 的大规模应用
  3. 拒绝做伸手党(程序猿)心得体会
  4. Proteus仿真-DS18B20温度传感器使用方法
  5. 基于BES蓝牙芯片PCBA测试程序接口实验
  6. 什么是HDMI延长器?HDMI延长器应用在什么场合
  7. 软件产品中的财务分析
  8. 第三章 外科手术队伍
  9. PostgreSQL 的时间差DATEDIFF
  10. STAHL触摸屏维修一体机显示屏ET-316-TX-TFT常见故障