题面

题解

加入一条线段,可以把它转化为在[L,R]区间内加一条线 y=ax+b (如果原线段与y轴平行,就相当于在{x1}处加一条线 y=max(y1,y2))

我们可以把它加到线段树上,线段树上每个点存一个区间内贯穿整个区间的一条对答案有贡献的线段(因为是贯穿整个区间,所以存一个 {a,b} 表示 y=ax+b 就行了)。

一条线段是这么加上去的:

查询要遍历路径上的所有点:

接下来,最大的问题就是,它会产生冲突!

当我们加一条线段到线段树上,而原来节点上就已经有了一条线段怎么办?

首先,如果其中一条线段凌驾于另一条之上,肯定直接判了嘛,

但是,出问题的就是两条线段交叉,

而线段树上的节点存不了“V”字形,也维护不了(除了写平衡树的大佬)

这里就要用到一个“启发式下传”的思想

一般的暴力想法就是先把原来的线段先下传了,再把新线段放上去:

稍微有点想法的人会先把“V”字形处理出来,并把两条线段拆开下传(虽然并没有什么*用):

这时候,较聪明的人就会想,为什么原来的地方要空着呢?把其中随便一条线段留在原处,对答案也没有影响,但是却快得多:

最后,深谙暴力优化精髓的人会想,数据肯定会卡每次下传的线段长度只比原先段短一点的情况,便把“V”字形两条线段中短的一条下传,

于是便优化出了正解:

我们会发现,每次一旦冲突,便会开始下传,每次下传的线段长度至少会减半,所以,下传复杂度为O(log),加线段复杂度就为O(log^2)

查询复杂度没变,总复杂度就为O(mlog^2)

CODE

#include<map>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 50005
#define MAXM 100005
#define LL long long
#define DB double
#define ENDL putchar('\n')
#define lowbit(x) ((-x)&(x))
//#define int LL
//#pragma GCC optimize(2)
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s=getchar();}
return f*x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k;
struct it{
DB x,y;
it(){x = y = 0;}
it(DB X,DB Y){x=X;y=Y;}
};
it cg(it a,it b) {
DB k = (a.y - b.y) / (a.x - b.x);
DB B = a.y - a.x * k;
return it(k,B);
}
it jd(it a,it b) {
DB xx = (b.y - a.y) / (a.x - b.x);
return it(xx,a.x*xx+a.y);
}
bool abov(it a,it st) {
DB y2 = a.x * st.x + st.y;
return a.y >= y2;
}
bool operator < (it a,it b) {return a.y < b.y;}
bool operator > (it a,it b) {return b < a;}
bool operator <= (it a,it b) {return a.y <= b.y;}
bool operator >= (it a,it b) {return b <= a;}
struct tr{
int l,r;
it st;
tr(){l=r=0;st=it(0,-1e9);}
}tre[MAXM<<4];
void maketree(int a,int l,int r) {
tre[a].l = l;tre[a].r = r;
if(l < r) {
int mid = (l+r)>>1;
maketree(a<<1,l,mid);
maketree(a<<1|1,mid+1,r);
}
return ;
}
void addtree(int a,int l,int r,it st) {
if(tre[a].l > r || tre[a].r < l) return ;
if(tre[a].l >= l && tre[a].r <= r) {
DB ll = (DB)tre[a].l,rr = (DB)tre[a].r;
it l1 = it(ll,ll*tre[a].st.x+tre[a].st.y);
it r1 = it(rr,rr*tre[a].st.x+tre[a].st.y);
it l2 = it(ll,ll*st.x+st.y),r2 = it(rr,rr*st.x+st.y);
if(l1 >= l2 && r1 >= r2) return ;
if(l2 >= l1 && r2 >= r1) {
tre[a].st = st; return ;
}
it md = jd(st,tre[a].st); int mid = (tre[a].l+tre[a].r)>>1;
it ls = (l1 >= l2 ? tre[a].st:st),rs = (r1 >= r2 ? tre[a].st:st);
if(md.x <= (DB)mid) tre[a].st = rs,addtree(a<<1,l,r,ls);
else tre[a].st = ls,addtree(a<<1|1,l,r,rs);
return ;
}
addtree(a<<1,l,r,st);addtree(a<<1|1,l,r,st);
return ;
}
DB query(int a,int ad) {
if(tre[a].l > ad || tre[a].r < ad) return -1e9;
if(tre[a].l == tre[a].r) {
return ad*tre[a].st.x + tre[a].st.y;
}
return max(ad*tre[a].st.x+tre[a].st.y,max(query(a<<1,ad),query(a<<1|1,ad)));
}
int main() {
n = read();m = read();
maketree(1,1,100000);
for(int i = 1;i <= n;i ++) {
it a,b;
a.x = (DB)read();
a.y = (DB)read();
b.x = (DB)read();
b.y = (DB)read();
if(a.x > b.x) swap(a,b);
it st;
if(a.x == b.x) st = it(0,max(a.y,b.y));
else st = cg(a,b);
int ll = (int)a.x,rr = (int)b.x;
addtree(1,ll,rr,st);
}
for(int i = 1;i <= m;i ++) {
k = read();
if(!k) {
it a,b;
a.x = (DB)read();
a.y = (DB)read();
b.x = (DB)read();
b.y = (DB)read();
if(a.x > b.x) swap(a,b);
it st;
if(a.x == b.x) st = it(0,max(a.y,b.y));
else st = cg(a,b);
int ll = (int)a.x,rr = (int)b.x;
addtree(1,ll,rr,st);
}
else {
int x0 = read();
DB ans = query(1,x0);
printf("%.4f\n",ans < -1e8 ? 0.0:ans);
}
}
return 0;
}

「雅礼集训 2017 Day2」线段游戏(线段树懒标记“启发式下传”,李超树)的更多相关文章

  1. #6034. 「雅礼集训 2017 Day2」线段游戏 李超树

    #6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统 ...

  2. 【loj6034】「雅礼集训 2017 Day2」线段游戏

    #6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB 时间限制:1000 ms 标准输入输出 题目类型:传统 评测方式:Special Judge 上传者: 匿名 题目描述 ...

  3. 「雅礼集训 2017 Day2」解题报告

    「雅礼集训 2017 Day2」水箱 我怎么知道这种题目都能构造树形结构. 根据高度构造一棵树,在树上倍增找到最大的小于约束条件高度的隔板,开一个 \(vector\) 记录一下,然后对于每个 \(v ...

  4. 【LOJ6029】「雅礼集训 2017 Day1」市场(线段树裸题)

    点此看题面 大致题意: 维护序列,支持区间加法,区间除法(向下取整),区间求\(min\)和区间求和. 线段树维护区间除法 区间加法.区间求\(min\)和区间求和都是线段树基本操作,因此略过不提. ...

  5. loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移

    $ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...

  6. loj#6034 「雅礼集训 2017 Day2」线段游戏

    分析 区间李超树板子题 代码 #include<bits/stdc++.h> using namespace std; #define db double const int inf = ...

  7. LOJ#6032. 「雅礼集训 2017 Day2」水箱

    传送门 首先可以有一个平方复杂度的 \(DP\) 设 \(f_{i,j}\) 表示前面 \(i\) 个小格,高度为 \(j\) 的最大答案 令 \(h_i\) 表示隔板 \(i\) 的高度 当 \(j ...

  8. LOJ#6048. 「雅礼集训 2017 Day10」数列(线段树)

    题面 传送门 题解 我的做法似乎非常复杂啊-- 首先最长上升子序列长度就等于把它反过来再接到前面求一遍,比方说把\(2134\)变成\(43122134\),实际上变化之后的求一个最长上升子序列和方案 ...

  9. 「雅礼集训 2017 Day2」水箱

    题目链接 题意分析 我们用\(f[i][j]\)表示当前到达第\(i\)个位置水位高度为\(j\)的答案 如果那么\(h[i]\)为\(i\)和\(i+1\)之间的支柱高度 那么如果\(j≤h[i]\ ...

随机推荐

  1. vue根据后端菜单自动生成路由(动态路由)

    vue根据后端菜单自动生成路由(动态路由) router.js import Vue from 'vue' import Router from 'vue-router' import store f ...

  2. JAVA面向对象之封装和调用

    一   面向对象 面向对象的三大特性   1 封装:概念:封装是把过程和数据私有化,打包封存起来,对数据访问只能通过指定的方式.简单的可以理解为你把钱存到银行里,银行专员首先要给你开一个账户,之后你的 ...

  3. 记安装AWVS14过程踩的坑

    由于之前的AWVS14用着用着无法扫描了,一扫就是失败,一气之下就重装系统了.重装系统后发现安装还是不行,折腾了好久,终于找到方法了. 安装acunetix_14.1.210324124.exe 没啥 ...

  4. gulp入门第一课你需要注意的

    安装 1.首先确保你已经正确安装了nodejs环境.然后以全局方式安装gulp. npm install -g gulp 2.初始化项目. npm init 3.如果想在安装的时候把gulp写进项目p ...

  5. 【python基础】第11回 数据类型内置方法 02

    本章内容概要 列表内置方法 字典内置方法 元组内置方法 集合内置方法 可变类型与不可变类型 本章内容详细 1.列表内置方法 list 列表在调用内置方法之后不会产生新的值 1.1 统计列表中的数据值的 ...

  6. 摸鱼人常备5个Python迷你项目,玩一整天不是问题(附源码)

    大家好鸭,我是小熊猫 在使用Python的过程中,我最喜欢的就是Python的各种第三方库,能够完成很多操作. 下面就给大家介绍5个通过Python构建的项目,以此来学习Python编程. 一.石头剪 ...

  7. MySQL通过binlog日志恢复数据

    一.查看下自己的MySQL是否开启了binlog日志 # 是否启用binlog日志 OFF:关闭 ON:开启 show variables like 'log_bin'; 二.开启binlog日志 在 ...

  8. 写for循环快捷生成方式

    在编写代码过程常常会使用到for循环,这里给大家介绍一种快捷写法len.fori+回车键(其中len为循环长度)举个栗子,编写10次循环 8.fori

  9. C# --- SqlserverHelper帮助类、快速实现增删改查

    using System;using System.Data; using System.Data.SqlClient; namespace Demo.WorkerService { public c ...

  10. NC201605 Bits

    NC201605 Bits 题目 题目描述 Nancy喜欢做游戏! 汉诺塔是一个神奇的游戏,神奇在哪里呢? 给出 \(3\) 根柱子,最开始时 \(n\) 个盘子按照大小被置于最左的柱子. 如果盘子数 ...