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}}\ ...
随机推荐
- SpringCloud Alibaba实战(5:子模块基本业务开发)
源码地址:https://gitee.com/fighter3/eshop-project.git 持续更新中-- 在上一节里,我们搭建了一个微服务项目的整体架构,并进行了版本控制. 接下来我们进一步 ...
- UF_EVAL 曲线或边分析
Open C UF_EVAL_ask_arc 圆形曲线或边分析,得到曲线或边的信息UF_EVAL_ask_ellipse 椭圆曲线或边分析,得到曲线或边的信息UF_EVAL_ask_hyperbo ...
- 【模板】关于vector的lower_bound和upper_bound以及vector基本用法 STL
关于lower_bound和upper_bound 共同点 函数组成: 一个数组元素的地址(或者数组名来表示这个数组的首地址,用来表示这个数组的开头比较的元素的地址,不一定要是首地址,只是用于比较的& ...
- Winform中用户自定义控件中外部设置子控件属性的方法
假设我们新建立一个用户自定义控件,由一个lable1和pictureBox1组成 此时我们在外部调用该控件,然后想动态改变lable1的值,我们该怎么办? 假设实例化的用户控件名为UserContro ...
- 基于ABP落地领域驱动设计-06.正确区分领域逻辑和应用逻辑
目录 系列文章 领域逻辑和应用逻辑 多应用层 示例:正确区分应用逻辑和领域逻辑 学习帮助 系列文章 基于ABP落地领域驱动设计-00.目录和前言 基于ABP落地领域驱动设计-01.全景图 基于ABP落 ...
- HTTP Cookies知识-查看、发送、获取、返回
我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 1 简介 HTTP Cookies是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求 ...
- Ubuntu安装部署Kafka
Ubuntu安装部署Kafka 环境: Ubuntu 18.04.4 LTS ,JDK1.8,kafka_2.12-2.3.1 确保已经安装了JDK,JDK安装过程不再赘述.可参考文章xxxx 一.下 ...
- Lc_704二分查找
package com.example.leetcode2; import java.util.*; /** * @description: 704. 二分查找 * 给定一个 n 个元素有序的(升序) ...
- 试着给VuePress添加登录授权支持,基于v-dialogs
背景介绍 VuePress是个不错的能基于Markdown快速构建静态网站的框架,初步来说,对外访问都是透明的. 但是可能因为一些保密需要,有些站点的文档,我们希望控制一下访问,所以我们借着别人的轮子 ...
- 2、oracle用户和权限
权限主要可以分成三类:系统权限.角色.对象权限,角色是一类系统权限的分组, Oracle 的角色存放在表 dba_roles 中,某角色包含的系统权限存放在 dba_sys_privs 中, 包含的对 ...