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

内存限制:256 MiB 时间限制:1000 ms 标准输入输出
题目类型:传统 评测方式:Special Judge
上传者: 匿名

题目描述

给出若干条线段,用 (x1,y2),(x2,y2) 表示其两端点坐标,现在要求支持两种操作:

  • 0 x1 y1 x2 y2 表示加入一条新的线段 (x1,y2),(x2,y2);
  • 1 x0 询问所有线段中,x 坐标在 x0 处的最高点的 y 坐标是什么,如果对应位置没有线段,则输出 0 。

输入格式

第一行两个正整数 n 、m 为初始的线段个数和操作个数。
接下来 n 行,每行四个整数,表示一条线段。
接下来 m 行,每行为一个操作 0 x1 y1 x2 y2 或 1 x0

输出格式

对于每一个询问操作,输出一行,为一个实数,当你的答案与标准答案误差不超过10^-2时,则视为正确。

样例

样例输入

3 4
0 -1 4 1
4 2 7 2
7 1 8 2
1 4
1 3
0 3 3 6 3
1 3

样例输出

2
0.5
3

数据范围与提示

对于 10% 的数据,n,m≤1000;
对于另外 20% 的数据,所有的 1 操作都在 0 操作之后;
对于另外 20% 的数据,所有线段的两端的 x 坐标都包含所有询问的 x 坐标,你可以将每条线段当做直线处理;
对于 100% 的数据,1≤n≤50000,1≤m≤150000 ,x1,x2,y1,y2 均为整数,0<x0≤10^5,−10^6≤x1,x2,y1,y2≤10^6。

题意:

在平面直角坐标系中给你$n$条线段,$m$次询问,每次询问$x$处一条$y$值最大的线段。

题解:

容易发现我们需要用一个数据结构维护每个$x$处$y$最大的线段,支持查询,修改操作。

考虑线段树维护覆盖$[l,r]$区间的$y$最大线段是否可行。

但如果两条线段同时覆盖$[l,r]$且交点在$[l,r]$内则无法确定取哪条。

换句话说,一条线段如果没有被完爆就都是有贡献的。

但如果我们考虑维护覆盖$[l,r]$区间且在$mid$处$y$最大的线段呢?

(子区间不维护与父区间相同的线段)

反证法易得,过$x$处最大的线段必然在线段树上从$[1,N]$到$[x,x]$的路径上任意一处$mid$最大。

这是一棵不下传父节点标记的标记永久化线段树,专业名词叫做李超树。

现在维护应该十分好想了。

(转自网络dalao,侵删)

每当在区间$[l,r]$更新一条线段时,

  • 若该线段没有完全覆盖该区间,则更新左儿子,右儿子
  • 若该线段完爆了该区间原有的线段,直接替换并不更新儿子
  • 若该线段在$mid$处大于该区间原有线段,将该区间维护的线段更新为该线段  
    • 若该线段斜率大于原有线段,则原有线段在$[l,mid]$处可能有贡献,在$[mid+1,r]$处不可能有贡献,用原有线段更新左儿子
    • 若该线段斜率小于原有线段,则原有线段在$[l,mid]$处不可能有贡献,在$[mid+1,r]$处可能有贡献,用原有线段更新右儿子
  • 若该线段在$mid$处小于该区间原有线段
    • 若该线段斜率大于原有线段,则该线段在$[l,mid]$处不可能有贡献,在$[mid+1,r]$处可能有贡献,用该线段更新右儿子
    • 若该线段斜率小于原有线段,则该线段在$[l,mid]$处可能有贡献,在$[mid+1,r]$处不可能有贡献,用该线段更新左儿子

查询时在线段树访问叶节点$[x0,x0]$的路径上取$max$即可。

线段维护双点或点截距均可。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio> using namespace std;
#define MAXN 100005
#define MAXM 500005
#define INF 0x7fffffff
#define ll long long struct node{
int l,r,x1,x2;
double y1,y2;
node(){
x1=-1e6;x2=1e6;
y1=y2=-1e7;
}
}tree[MAXN<<];
inline int read(){
int x=,f=;
char c=getchar();
for(;!isdigit(c);c=getchar())
if(c=='-')
f=-;
for(;isdigit(c);c=getchar())
x=x*+c-'';
return x*f;
} double gety(int x0,int x1,int x2,double y1,double y2){
if(x1==x2) return max(y1,y2);
double k=(y1-y2+0.0)/(x1-x2+0.0);
double b=(y1+0.0)-k*(x1+0.0);
return k*(x0+0.0)+b;
} void build(int l,int r,int k){
//cout<<l<<":"<<r<<":"<<k<<endl;
tree[k].l=l,tree[k].r=r;
if(l==r) return;
int mid=(l+r)>>;
build(l,mid,k<<);
build(mid+,r,k<<|);
return;
} void insert(int x1,int x2,double y1,double y2,int k){
int mid=(tree[k].l+tree[k].r)>>;
//cout<<k<<":"<<tree[k].l<<":"<<tree[k].r<<endl;
if(tree[k].l>x2 || tree[k].r<x1) return;
if(x1<=tree[k].l && tree[k].r<=x2){
if(gety(mid,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2)<gety(mid,x1,x2,y1,y2)){
//cout<<mid<<" "<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
if(gety(tree[k].l,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2)>gety(tree[k].l,x1,x2,y1,y2)) insert(tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2,k<<);
if(gety(tree[k].r,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2)>gety(tree[k].r,x1,x2,y1,y2)) insert(tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2,k<<|);
tree[k].x1=x1,tree[k].x2=x2;tree[k].y1=y1,tree[k].y2=y2;
}
if(gety(mid,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2)>gety(mid,x1,x2,y1,y2)){
if(gety(tree[k].l,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2)<gety(tree[k].l,x1,x2,y1,y2)) insert(x1,x2,y1,y2,k<<);
if(gety(tree[k].r,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2)<gety(tree[k].r,x1,x2,y1,y2)) insert(x1,x2,y1,y2,k<<|);
}
return;
}
if(x1<=mid) insert(x1,x2,y1,y2,k<<);
if(x2>mid) insert(x1,x2,y1,y2,k<<|);
return;
} double query(int x0,int k){
if(tree[k].l==tree[k].r)
//cout<<k<<":"<<tree[k].l<<":"<<tree[k].r<<endl;
return gety(x0,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2);
int mid=(tree[k].l+tree[k].r)>>;
double t1=gety(x0,tree[k].x1,tree[k].x2,tree[k].y1,tree[k].y2);
//cout<<x0<<":"<<tree[k].x1<<":"<<tree[k].x2<<":"<<tree[k].y1<<":"<<tree[k].y2<<endl;
//cout<<t1<<endl;
if(x0<=mid) return max(t1,query(x0,k<<));
else return max(t1,query(x0,k<<|));
} int main(){
//freopen("C1.in","r",stdin);
//freopen("segment.out","w",stdout);
int N=read(),M=read();
build(,1e5,);
for(int i=;i<=N;i++){
int x1,x2;
double y1,y2;
cin>>x1>>y1>>x2>>y2;
if(x1>x2) swap(x1,x2),swap(y1,y2);
insert(x1,x2,y1,y2,);
}
for(int i=;i<=M;i++){
int flag=read();
if(!flag){
int x1,x2;
double y1,y2;
cin>>x1>>y1>>x2>>y2;
if(x1>x2) swap(x1,x2),swap(y1,y2);
insert(x1,x2,y1,y2,);
}
else{
int x0;cin>>x0;
double k=query(x0,);
if(k==-1e7) printf("%d\n",);
else printf("%.2lf\n",k);
}
}
return ;
}
/*
3 4
0 -1 4 1
4 2 7 2
7 1 8 2
1 4
1 3
0 3 3 6 3
1 3
*/

【loj6034】「雅礼集训 2017 Day2」线段游戏的更多相关文章

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

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

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

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

  3. 「雅礼集训 2017 Day2」线段游戏(线段树懒标记“启发式下传”,李超树)

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

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

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

  5. loj#6033. 「雅礼集训 2017 Day2」棋盘游戏(二分图博弈)

    题意 链接 Sol 第一次做在二分图上博弈的题..感觉思路真是清奇.. 首先将图黑白染色. 对于某个点,若它一定在最大匹配上,那么Bob必胜.因为Bob可以一直沿着匹配边都,Alice只能走非匹配边. ...

  6. loj#6032. 「雅礼集训 2017 Day2」水箱(并查集 贪心 扫描线)

    题意 链接 Sol 神仙题+神仙做法%%%%%%%% 我再来复述一遍.. 首先按照\(y\)坐标排序,然后维护一个扫描线从低处往高处考虑. 一个连通块的内状态使用两个变量即可维护\(ans\)表示联通 ...

  7. [LOJ#6033]. 「雅礼集训 2017 Day2」棋盘游戏[二分图博弈、匈牙利算法]

    题意 题目链接 分析 二分图博弈经典模型,首先将棋盘二分图染色. 考虑在某个最大匹配中: 如果存在完美匹配则先手必败,因为先手选定的任何一个起点都在完美匹配中,而后手则只需要走这个点的匹配点,然后先手 ...

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

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

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

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

随机推荐

  1. (转)我在北京工作这几年 – 一个软件工程师的反省

    我于2007年来到北京,在北京工作这些年,先后在NEC.风行.百度几家公司担任软件工程师的职务.NEC是一家具有百年历史的传统日企,在知春路的分公司叫日电电子,我们部门主要从事机顶盒.数字电视上嵌入式 ...

  2. dsBlog_杂类

    C++,MFC的综合类的博客. 1. http://www.cnblogs.com/mfryf/category/354043.html

  3. 三张图教你生成一个Android jar 库。

    我看到非常多教人使用第三方开源组件的Android教程.都是在教基于源代码project的库导入,个人觉得非常不妥,觉得最恰当的方式是把源代码project生成一个jar再导入到目标project上使 ...

  4. group by where having 联合使用

    having子句与where有相似之处但也有区别,都是设定条件的语句.在查询过程中聚合语句(sum,min,max,avg,count)要比having子句优先执行.而where子句在查询过程中执行优 ...

  5. Cats transport(codeforces311B)(斜率优化)

    \(Cats Transport\) 感觉这道题题面不好讲,就自翻了一个新的,希望有助于大家理解其思路: 大致题意: \(wch\) 的家里有 \(N\) 座山(山呈直线分布,第 \(i-1\) 座山 ...

  6. ubuntu 本地和服务器scp文件传输

    安装 SSH(Secure Shell) 服务以提供远程管理服务 sudo apt-get install ssh SSH 远程登入 Ubuntu 机 ssh username@192.168.0.1 ...

  7. ActiveMQ P2P模型 观察者消费

    生餐者: package clc.active.listener; import org.apache.activemq.ActiveMQConnectionFactory; import org.t ...

  8. SDUT OJ 周赛 找有毒的那杯水(思维逻辑 + 分治思想 )

    你打我啊 Time Limit: 500ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 最近看了一个非常好玩的题,如果有972杯水,其中有971个没有毒的,1个有 ...

  9. POJ2253 Frogger —— 最短路变形

    题目链接:http://poj.org/problem?id=2253 Frogger Time Limit: 1000MS   Memory Limit: 65536K Total Submissi ...

  10. 教你开发jQuery插件

    jQuery插件开发模式 软件开发过程中是需要一定的设计模式来指导开发的,有了模式,我们就能更好地组织我们的代码,并且从这些前人总结出来的模式中学到很多好的实践. 根据<jQuery高级编程&g ...