原题链接寄了
题面
有 n n n 个线段。第 i i i 条线段连接 ( a i , b i ) , ( c i , d i ) (a_i,b_i),(c_i,d_i) (ai,bi),(ci,di)。同时这些直线满足如下性质:
- 对于任意线段,满足 c i > a i , d i < b i c_i > a_i,d_i < b_i ci>ai,di<bi。
- 对于任意两条线段,其不包含任何公共点(包括端点在内)。
Q Q Q 次询问,每次询问给出一个点 ( x i , y i ) (x_i,y_i) (xi,yi)。询问对于所有 n n n 条线段,其落在以 ( − C , − C ) (-C,-C) (−C,−C) 为左下角, ( x i , y i ) (x_i,y_i) (xi,yi) 为右上角的矩形内的部分的长度之和。
输入格式
第一行一个正整数 n n n。
接下来 n n n 行,每行四个整数 a i , b i , c i , d i a_i,b_i,c_i,d_i ai,bi,ci,di。
接下来一行一个正整数 Q Q Q。
接下来 Q Q Q 行,一行两个整数 x i , y i x_i,y_i xi,yi。
输出格式
Q Q Q 行,一行一个非负实数,表示答案。
假定输入的所有的线段长度之和为 S S S, 你的答案被认为是正确的当且仅当对于每次询问,你和标准输入的绝对误差不超过 1 0 − 10 max { S , 1 } 10^{-10}\max\{S,1\} 10−10max{S,1}。
换而言之,假设你的输出是 a a a,标准答案是 b b b,则你的答案被认为是正确的当且仅当 ∣ a − b ∣ ≤ 1 0 − 10 max { S , 1 } |a-b|≤10^{-10}\max\{S,1\} ∣a−b∣≤10−10max{S,1}。
数据范围
Subtask 1: n , Q ⩽ 50 n,Q\leqslant 50 n,Q⩽50 (8%)
Subtask 2: n , Q ⩽ 5000 n,Q \leqslant 5000 n,Q⩽5000 (10%)
Subtask 3: 线段长度之和不超过 1 0 6 10^6 106 (22%)
Subtask 4: 对于所有的线段,满足 a i + b i = c i + d i a_i+b_i = c_i+d_i ai+bi=ci+di (15%)
Subtask 5: 没特殊限制 (45%)
对于所有测试数据,满足 C = 3 × 1 0 5 , ∣ a i ∣ , ∣ b i ∣ , ∣ c i ∣ , ∣ d i ∣ , ∣ x i ∣ , ∣ y i ∣ ⩽ 3 × 1 0 5 , n ⩽ 1 × 1 0 5 , Q ⩽ 1.5 × 1 0 5 C = 3×10^5, |a_i|,|b_i|,|c_i|,|d_i|,|x_i|,|y_i| \leqslant 3×10^5, n\leqslant 1×10^5,Q\leqslant 1.5×10^5 C=3×105,∣ai∣,∣bi∣,∣ci∣,∣di∣,∣xi∣,∣yi∣⩽3×105,n⩽1×105,Q⩽1.5×105。
题解
这题和计算几何没什么关系,就一个SB数据结构题。
首先把答案转化为 x ∈ R , y ≤ y i x\in R,y\le y_i x∈R,y≤yi 的长度和减去 x > x i , y ≤ y i x>x_i,y\le y_i x>xi,y≤yi 的长度和。前者可以直接沿 y y y 轴扫描线,然后分线段与扫描线是否相交两种情况,不相交直接统计和,相交的差分处理。
对于后者,我们仍然分两种情况讨论:
线段与边框不相交,我们可以直接用树状数组维护后缀和;
线段与边框相交,此时由于线段的朝向,最多只会有一个交点,我们分别沿
x
x
x 轴和
y
y
y 轴做扫描线,把线段放平衡树上即可求得与两条边框相交的线段长,同样的差分处理。
现在最大的问题是扫描线移动的过程中,平衡树上的线段的次序问题。由于这题的性质,线段没有交点,所以在平衡树上同时存在的线段次序不会变化,直接放心做就好了。
最后是一些精度问题,比如当你要删去平衡树上的某点时,千万不要用double
参数的方式来查找它,这样会导致删去一片点或者什么也没删,你只能找到要删的点往父亲爬。
代码
我也不知道是不是对的,反正民间数据过了。
#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define lll __int128
#define uns unsigned
#define fi first
#define se second
#define IF (it->fi)
#define IS (it->se)
#define END putchar('\n')
#define lowbit(x) ((x)&-(x))
#define inline jzm
using namespace std;
const int MAXN=6e5+5;
const ll INF=1e18;
ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int ptf[50],lpt;
void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
ptf[lpt=1]=x%10;
while(x>9)x/=10,ptf[++lpt]=x%10;
while(lpt>0)putchar(ptf[lpt--]^48);
if(c>0)putchar(c);
}
const double eps=1e-14,E=1;
const int AD=3e5+2,L=1,R=AD<<1;
int n,m;
struct itn{
int a,b,c,d;double len;
void readin(){
a=read(),b=read(),c=read(),d=read();
len=sqrt(1ll*(a-c)*(a-c)+1ll*(b-d)*(b-d));
}
double cty(int y){return c-E*(c-a)/(b-d)*(y-d);}
}f[MAXN];
int X[MAXN>>1],Y[MAXN>>1];
double ans[MAXN>>1];
vector<int>ad[MAXN],sk[MAXN];
#define pii pair<int,int>
mt19937 Rand(114514);
struct fhq{
int ls,rs,val,fa;double a,b,s,g;fhq(){}
fhq(double A,double B){
s=a=A,g=b=B,ls=rs=0,val=Rand();
}
}t[MAXN];
int root;
void upd(int x){
t[x].s=t[t[x].ls].s+t[t[x].rs].s+t[x].a;
t[x].g=t[t[x].ls].g+t[t[x].rs].g+t[x].b;
if(t[x].ls)t[t[x].ls].fa=x;
if(t[x].rs)t[t[x].rs].fa=x;
}
pii split(int x,int y,double k){
t[x].fa=0;
if(!x)return pii(0,0);
pii res;
if(f[x].cty(y)>k)res=split(t[x].ls,y,k),t[x].ls=res.se,upd(x),res.se=x;
else res=split(t[x].rs,y,k),t[x].rs=res.fi,upd(x),res.fi=x;
return res;
}
int mergg(int x,int y){
t[x].fa=t[y].fa=0;
if(!x||!y)return x^y;
int res;
if(t[x].val<t[y].val)t[x].rs=mergg(t[x].rs,y),upd(x),res=x;
else t[y].ls=mergg(x,t[y].ls),upd(y),res=y;
return res;
}
void delp(int x){
int y=mergg(t[x].ls,t[x].rs);
while(t[x].fa>0){
if(x==t[t[x].fa].ls)x=t[x].fa,t[x].ls=y,upd(x),y=x;
else x=t[x].fa,t[x].rs=y,upd(x),y=x;
}root=y;
}
double bf[MAXN];
void badd(int x,double d){
for(;x<=R;x+=lowbit(x))bf[x]+=d;
}
double bsum(int x){
double res=0;
for(;x>0;x&=(x-1))res+=bf[x];
return res;
}
void prt(){for(int i=1;i<=m;i++)printf("%.10f\n",ans[i]);}
int main()
{
n=read();
for(int i=1;i<=n;i++)f[i].readin();
m=read();
for(int i=1;i<=n;i++)ad[f[i].b+AD].push_back(i);
for(int i=1;i<=m;i++)X[i]=read(),Y[i]=read(),sk[Y[i]+AD].push_back(i);
for(int i=1;i<=R;i++){
for(int x:ad[i])badd(f[x].a+AD,f[x].len);
for(int x:sk[i])ans[x]+=bsum(X[x]+AD-1);
ad[i].clear();
}
for(int i=1;i<=n;i++)ad[f[i].d+AD].push_back(i),ad[f[i].b+AD].push_back(-i);
for(int i=1;i<=R;i++){
for(int xx:ad[i]){
int x=abs(xx);
if(xx>0){
pii y=split(root,i-AD,f[x].cty(i-AD));
double b=f[x].len/(f[x].b-f[x].d);
t[x]=fhq(b*(R-AD-f[x].d),b);
root=mergg(y.fi,mergg(x,y.se));
}else delp(x);
}
for(int x:sk[i]){
ans[x]+=t[root].s-t[root].g*(R-i);
pii y=split(root,i-AD,X[x]-eps);
ans[x]-=t[y.se].s-t[y.se].g*(R-i);
root=mergg(y.fi,y.se);
}ad[i].clear(),sk[i].clear();
}
for(int i=1;i<=n;i++){
swap(f[i].a,f[i].d),swap(f[i].b,f[i].c);
ad[f[i].d+AD+1].push_back(i),ad[f[i].b+AD+1].push_back(-i);
}
for(int i=1;i<=m;i++)swap(X[i],Y[i]),sk[Y[i]+AD].push_back(i);
root=0;
for(int i=1;i<=R;i++){
for(int xx:ad[i]){
int x=abs(xx);
if(xx>0){
pii y=split(root,i-AD,f[x].cty(i-AD));
double b=f[x].len/(f[x].b-f[x].d);
t[x]=fhq(b*(f[x].b+AD),b);
root=mergg(y.fi,mergg(x,y.se));
}else delp(x);
}
for(int x:sk[i]){
pii y=split(root,i-AD,X[x]-eps);
ans[x]-=t[y.fi].s-t[y.fi].g*i;
root=mergg(y.fi,y.se);
}ad[i].clear(),sk[i].clear();
}prt();
return 0;
}