P6106 [Ynoi2010] Self Adjusting Top Tree
P6106 [Ynoi2010] Self Adjusting Top Tree
题意
给出平面直角坐标系上若干不与坐标轴平行的处于第一象限的互不相交的线段,多次询问平面中一个第一象限的矩形与这些线段相交部分的长度长度和与所有线段长度和的比值。给出的所有坐标 \(\in[1,10^6]\)。
思路
假设所有线段的斜率都是正的,考虑将询问差分成四个前缀矩形。我们只需要考虑统计若干斜率为正的互不相交的线段与一个前缀矩形的交就行了。
经典套路:若线段互不相交,在扫描线时其相对顺序不会变。比如在用与 \(y\) 轴平行的直线做扫描线时线段与其相交的 \(y\) 坐标相对大小不会变。再比如,用以原点为端点的射线做扫描线时线段与其交点到原点距离的相对大小不会变。
因此,我们用平行于 \(y\) 轴的直线做扫描线,用平衡树维护区间线段长度的和。即,维护单位 \(x\) 区间线段长度增量,维护区间线段长度和,支持区间加,支持插入删除。因为线段斜率为正且询问为前缀矩形,所以没有线段另一端不在矩形内的情况。这样就能统计且恰好统计所有与矩形右侧相交的线段的长度和。
统计所有与矩形上侧相交的长度和只需要将扫描线变为与 \(x\) 平行的再做一遍就可以了。为了使与顶点交的线段只统计一次,可以将翻转前后其中一次的所有查询减去 eps 使其不合法。
对于所有完全被包含的线段,发现只要线段右上端在矩形内就全部在矩形内。做一遍二维数点即可。
对于所有斜率为负的线段,将它们和询问矩形上下反转,然后再做一遍上述过程即可。
至此,所有的贡献被统计完毕。实现时请注意细节。
代码我觉得我写的还行,就放出来,看懂了的应该挺容易实现的,没看懂的可以参考代码。
实现
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=x*10+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=4e5+10,maxm=1e6+10,N=1e6+1;
double eps=1e-6;
int n,m,cnt[2],c[2][maxn];
double ans[maxn];
struct vec{
int x,y;
vec(int x=0,int y=0):x(x),y(y){}
inline void updown(){y=N-y;}
};
int X;
struct seg{
vec a,b;
seg(){}
seg(vec a,vec b):a(a),b(b){}
inline double length(){return sqrt(1.*(b.y-a.y)*(b.y-a.y)+1.*(b.x-a.x)*(b.x-a.x));}
inline void updown(){a.updown(),b.updown();}
inline double y() {return a.y+1.0*(X-a.x)*(b.y-a.y)/(b.x-a.x);}
}a[maxn],b[2][maxn];
struct que{
int x;
double y;
int tp,id;
que(){}
que(int x,double y,int tp,int id):x(x),y(y),tp(tp),id(id){}
bool operator < (const que &b) const {return x<b.x;}
}q[maxn<<2];
#define ls son[x][0]
#define rs son[x][1]
double s1[maxn],s2[maxn],s[maxn],tag[maxn],sum[maxn];
int tot,rt,e[maxn],son[maxn][2],rnd[maxn];
inline int newnode(int i){e[++tot]=i,s1[tot]=s[tot]=a[i].length()/(a[i].b.x-a[i].a.x),s2[tot]=tag[tot]=son[tot][0]=son[tot][1]=sum[tot]=0,rnd[tot]=rand();return tot;}
inline void add(int x,int a){s2[x]+=a*s1[x],sum[x]+=a,tag[x]+=a;}
inline void pushdown(int x){if(tag[x]) add(ls,tag[x]),add(rs,tag[x]),tag[x]=0;}
inline void pushup(int x){s2[x]=s2[ls]+s2[rs]+sum[x]*s[x],s1[x]=s1[ls]+s1[rs]+s[x];}
void split(int x,double k,int &a,int &b){
if(!x) return a=b=0,void();
pushdown(x);
if(k>=star::a[e[x]].y()) a=x,split(rs,k,rs,b);
else b=x,split(ls,k,a,ls);
pushup(x);
}
int merge(int a,int b){
if(!a or !b) return a|b;
if(rnd[a]<rnd[b]){
pushdown(a),son[a][1]=merge(son[a][1],b),pushup(a);
return a;
}else{
pushdown(b),son[b][0]=merge(a,son[b][0]),pushup(b);
return b;
}
}
inline void insert(int i){
int x,y;
split(rt,a[i].y(),x,y);
rt=merge(merge(x,newnode(i)),y);
}
inline void update(int i){
int a,b;
split(rt,star::a[i].y(),a,b);
static int st[maxn];
int top=0,x,y;
for(y=0,x=a;rs;y=x,x=rs) pushdown(x),st[++top]=x;
if(e[x]!=i) return rt=merge(merge(a,newnode(i)),b),void();
if(!y) a=son[a][0];
else son[y][1]=merge(ls,rs);
while(top) pushup(st[top--]);
rt=merge(a,b);
}
inline double query(double k){
int x,y;
split(rt,k,x,y);
double ans=s2[x];
rt=merge(x,y);
return ans;
}
#undef ls
#undef rs
double C[maxm];
inline void Insert(int x,double k){for(;x<=N;x+=x&-x) C[x]+=k;}
inline double Query(int x){double ans=0;for(;x;x-=x&-x) ans+=C[x];return ans;}
inline void solve(int *c,int n,seg *b){
int tot=0;
for(int i=1;i<=m;i++) q[++tot]=que(b[i].b.x,b[i].b.y-eps,1,i),q[++tot]=que(b[i].a.x,b[i].b.y-eps,-1,i),q[++tot]=que(b[i].b.x,b[i].a.y-eps,-1,i),q[++tot]=que(b[i].a.x,b[i].a.y-eps,1,i);
sort(q+1,q+1+tot);
if(eps!=0){
sort(c+1,c+1+n,[](int x,int y){return a[x].b.x<a[y].b.x;});
for(int i=1,j=1;i<=tot;i++){
while(j<=n and a[c[j]].b.x<=q[i].x) Insert(a[c[j]].b.y,a[c[j]].length()),j++;
ans[q[i].id]+=q[i].tp*Query(q[i].y+eps);
}
}
static pair<int,int> op[maxn<<1];
for(int i=1;i<=n;i++) op[i*2-1]=make_pair(a[c[i]].a.x,c[i]),op[i*2]=make_pair(a[c[i]].b.x,c[i]);
n<<=1;
sort(op+1,op+1+n);
X=0;
for(int i=1,j=1;i<=tot;i++){
while(j<=n and op[j].first<=q[i].x) add(rt,op[j].first-X),X=op[j].first,update(op[j].second),j++;
add(rt,q[i].x-X),X=q[i].x,ans[q[i].id]+=q[i].tp*query(q[i].y);
}
memset(C,0,sizeof C),rt=tot=0;
}
inline void solve(){
solve(c[0],cnt[0],b[0]);
solve(c[1],cnt[1],b[1]);
}
inline void work(){
srand(time(0));
n=read();
double len=0;
for(int i=1;i<=n;i++){
a[i].a.x=read(),a[i].a.y=read(),a[i].b.x=read(),a[i].b.y=read();
if(a[i].a.x>a[i].b.x) swap(a[i].a,a[i].b);
int t=a[i].a.y>a[i].b.y;
if(t) a[i].updown();
c[t][++cnt[t]]=i;
len+=a[i].length();
}
m=read();
for(int i=1;i<=m;i++) b[0][i].a.x=read(),b[0][i].a.y=read(),b[0][i].b.x=read(),b[0][i].b.y=read(),b[1][i]=b[0][i],b[1][i].updown(),swap(b[1][i].a.y,b[1][i].b.y);
solve();
for(int i=1;i<=n;i++) swap(a[i].a.x,a[i].a.y),swap(a[i].b.x,a[i].b.y);
for(int i=1;i<=m;i++) swap(b[0][i].a.x,b[0][i].a.y),swap(b[0][i].b.x,b[0][i].b.y),swap(b[1][i].a.x,b[1][i].a.y),swap(b[1][i].b.x,b[1][i].b.y);
eps=0;
solve();
for(int i=1;i<=m;i++) printf("%.10f\n",ans[i]/len);
}
}
signed main(){
star::work();
return 0;
}
P6106 [Ynoi2010] Self Adjusting Top Tree的更多相关文章
- 动态树(LCT、Top Tree、ETT)
LCT Upd: 一个细节:假如我们要修改某个节点的数据,那么要先把它makeroot再修改,改完之后pushup. LCT是一种维护森林的数据结构,本质是用Splay维护实链剖分. 实链剖分大概是这 ...
- Size Balance Tree(SBT模板整理)
/* * tree[x].left 表示以 x 为节点的左儿子 * tree[x].right 表示以 x 为节点的右儿子 * tree[x].size 表示以 x 为根的节点的个数(大小) */ s ...
- [bzoj3282]Tree (lct)
昨天看了一天的lct..当然幸好最后看懂了(也许吧..) 论善良学长的重要性T_T,老司机带带我! 这题主要是删边的时候还要判断一下..蒟蒻一开始天真的以为存在的边才能删结果吃了一发wa... 事实是 ...
- Link-Cut Tree指针模板
模板: 以下为弹飞绵羊代码: #define Troy #include "bits/stdc++.h" using namespace std; ; inline int rea ...
- 【BZOJ2631】tree
Description 一棵n个点的树.每一个点的初始权值为1. 对于这棵树有q个操作,每一个操作为下面四种操作之中的一个: + u v c:将u到v的路径上的点的权值都加上自然数c: - u1 v1 ...
- PAT 1086 Tree Traversals Again[中序转后序][难]
1086 Tree Traversals Again(25 分) An inorder binary tree traversal can be implemented in a non-recurs ...
- LeetCode Construct Binary Tree from String
原题链接在这里:https://leetcode.com/problems/construct-binary-tree-from-string/description/ 题目: You need to ...
- HDU 6191 Query on A Tree(字典树+离线)
Query on A Tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Othe ...
- 【置顶】Trotyl's OI tree
\(\rm thx\):@\(\rm UntilMadow\) ! \(\color{Green}{\rm Pupil}\) :只会一点点 \(\color{blue}{\text{Expert}}\ ...
随机推荐
- 包及权限配置&java存储机理绘制
包及权限配置 包的声明和导入 //声明 package aa.bb.cc; public class A{;} class B{;} //即在java输出目录aa.bb.cc中放入编译后的A.clas ...
- java后端知识点梳理——java集合
集合概览 Java中的集合,从上层接口上看分为了两类,Map和Collection.Map是和Collection并列的集合上层接口,没有继承关系. Java中的常见集合可以概括如下. Map接口和C ...
- Pytest测试框架入门到精通(一)
Python测试框架之前一直用的是unittest+HTMLTestRunner,听到有人说Pytest很好用,所以这边给大家介绍一下Pytest的使用 pytest是一个非常成熟的全功能的Pytho ...
- .NET Core/.NET5/.NET6 开源项目汇总9:客户端跨平台UI框架
系列目录 [已更新最新开发文章,点击查看详细] .NET Core 实现了跨平台,支持在 Windwos.Linux.macOS上开发与部署,但是也仅限于Web应用程序.对于Windows桌面 ...
- kerberos认证协议爱情故事
0x01.kerberos简介 kerberos是一种域内认证协议,Kerberos的标志是三头狗,狗头分别代表以下角色: Client Server KDC(Key Distribution Cen ...
- 11、gitlab和Jenkins整合(2)
5.补充: (1)构建说明: 1)Jenkins会基于一些处理器任务后,构建发布一个稳健指数 (从0-100 ),这些任务一般以插件的方式实现. 2)它们可能包括单元测试(JUnit).覆盖率(Cob ...
- hdu 6050 Funny Function 矩阵快速幂
就算告诉我是矩阵快速幂我也推不出递推式呀!!! 官方题解: 对于任意i>=1,当j>=3时,有通过归纳法可以得到 进而推导出 后来自己重新推导了一遍 #include <iostre ...
- 为什么要鼓励小型企业使用CRM系统
如果你是一家小公司的管理者,我相信你必须对工作流程.客户.市场销售.市场营销推广等业务流程进行总体规划和管理方法,这往往会使你的心有馀而力不足,引起 繁忙.心有馀而力不足.交流受到阻碍.管理方法和这样 ...
- Linux 3.16 release 贡献度
内核 3.16 release 的贡献度可以在下面网页看到: http://www.remword.com/kps_result/3.16_whole.html 一共发布了 12802 个补丁, 18 ...
- [源码解析] 深度学习分布式训练框架 horovod (14) --- 弹性训练发现节点 & State
[源码解析] 深度学习分布式训练框架 horovod (14) --- 弹性训练发现节点 & State 目录 [源码解析] 深度学习分布式训练框架 horovod (14) --- 弹性训练 ...