bzoj 3165
题意:
给出平面上一些线段,在线询问与x=x0相交的线段中,交点y最大的线段的标号,支持添加线段。
大概思路:
用线段树维护,线段树每个线段记录贯穿(左右端点在该区间外或上)的原线段中能覆盖其它贯穿该线段的原线段(即每个线段树线段记录贯穿该线段的所有原线段中“最高”的)
细节:
添加原线段s到线段树线段nd:
如果s不能覆盖,根据s的大小传递到左儿子或右儿子或都传
如果s覆盖,
如果原本没有线段,则直接设置为s
如果有线段ss,求s与ss的交点,将短(比较x上投影的长度)的线段“压”到交点所在儿子,长的变成本区间的。
(要注意如果y相等,比较标号)
查询x
查询覆盖x的所有区间的线段树线段对应的原线段(有的话)中在x处y最大的。
/**************************************************************
Problem: 3165
User: idy002
Language: C++
Result: Accepted
Time:1492 ms
Memory:4244 kb
****************************************************************/ #include <cstdio>
#include <cmath>
#include <vector>
#define lson nd<<1
#define rson nd<<1|1
#define maxn 100010
#define modx 39989
#define mody 1000000000
#define eps 1e-10
using namespace std; int sg( double x ) {
return (x>-eps)-(x<eps);
}
struct Line {
int lf, rg;
double k, b;
Line(){}
Line( int x0, int y0, int x1, int y1 ) {
lf = min( x0, x1 );
rg = max( x0, x1 );
if( x0==x1 ) {
k = 0.0;
b = max( y0, y1 );
} else {
k = (y1-y0+0.0)/(x1-x0);
b = y1-x1*k;
}
}
inline double f( int x ) {
return k*x+b;
}
inline double cx( Line &c ) {
return (c.b-b)/(k-c.k);
}
}; int n;
int ltot;
Line lns[maxn];
int v[(modx+)<<];
int wi[modx+];
double wy[modx+]; void update( int x, int i ) {
double ny = lns[i].f(x);
int s=sg(ny-wy[x]);
if( !wi[x] || (s> || (s==&&i<wi[x])) ) {
wi[x] = i;
wy[x] = ny;
}
}
void modify( int i, int nd, int lf, int rg ) {
if( lns[i].lf<=lf && rg<=lns[i].rg ) {
if( !v[nd] ) {
v[nd] = i;
return;
}
bool lu = sg( lns[i].f(lf)-lns[v[nd]].f(lf) )>;
bool ru = sg( lns[i].f(rg)-lns[v[nd]].f(rg) )>;
int mid=(lf+rg)>>;
if( lu && ru ) {
v[nd] = i;
} else if( lu || ru ) {
int lm = floor( lns[i].cx( lns[v[nd]] ) );
if( lm<=mid && lu ) {
modify( i, lson, lf, mid );
} else if( lm<=mid && ru ) {
modify( v[nd], lson, lf, mid );
v[nd] = i;
} else if( lu ) {
modify( v[nd], rson, mid+, rg );
v[nd] = i;
} else {
modify( i, rson, mid+, rg );
}
} else {
update( lf, i );
update( rg, i );
}
return;
}
int mid = (lf+rg)>>;
if( lns[i].lf<=mid ) modify( i, lson, lf, mid );
if( lns[i].rg>mid ) modify( i, rson, mid+, rg );
}
int query( int x ) {
int nd = ;
int lf = , rg = modx;
int rt = ;
double cury = -1.0;
while() {
if( v[nd] ) {
double ny = lns[v[nd]].f(x);
int s = sg( ny-cury );
if( s> || (s==&&v[nd]<rt) ) {
rt = v[nd];
cury = ny;
}
}
if( lf==rg ) break;
int mid=(lf+rg)>>;
if( x<=mid ) {
nd = lson;
rg=mid;
} else {
nd = rson;
lf=mid+;
}
}
int s = sg( wy[x]-cury );
if( s> || (s==&&wi[x]<rt) )
return wi[x];
return rt;
} int main() {
int T, lastans=;
scanf( "%d", &T );
while( T-- ) {
int opt;
scanf( "%d", &opt );
if( opt== ) {
int x;
scanf( "%d", &x );
x = ((x+lastans-)%modx+);
printf( "%d\n", lastans=query(x) );
} else {
int x0, y0, x1, y1;
scanf( "%d%d%d%d", &x0, &y0, &x1, &y1 );
x0 = (x0+lastans-)%modx+;
y0 = (y0+lastans-)%mody+;
x1 = (x1+lastans-)%modx+;
y1 = (y1+lastans-)%mody+;
lns[++ltot] = Line(x0,y0,x1,y1);
modify( ltot, , , modx );
}
}
}
bzoj 3165的更多相关文章
- bzoj 3165: [Heoi2013]Segment 动态凸壳
3165: [Heoi2013]Segment Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 202 Solved: 89[Submit][Stat ...
- BZOJ.3165.[HEOI2013]Segment(李超线段树)
BZOJ 洛谷 对于线段,依旧是存斜率即可. 表示精度误差一点都不需要管啊/托腮 就我一个人看成了mod(10^9+1)吗.. //4248kb 892ms #include <cstdio&g ...
- BZOJ 3165: [Heoi2013]Segment
3165: [Heoi2013]Segment Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 465 Solved: 187[Submit][Sta ...
- Bzoj 3165 [Heoi2013]Segment题解
3165: [Heoi2013]Segment Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 668 Solved: 276[Submit][Sta ...
- 【BZOJ 3165】【HEOI 2013】Segment
往区间上覆盖一次函数,做法是用线段树维护标记永久化. 每次都忘了线段树要4倍空间,第一次交总是RE,再这么手残的话考场上就真的要犯逗了. #include<cstdio> #include ...
- BZOJ 3165 Segment
同上题. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm&g ...
- 【BZOJ 3165】 [Heoi2013]Segment 李超线段树
所谓李超线段树就是解决此题一类的问题(线段覆盖查询点最大(小)),把原本计算几何的题目变成了简单的线段树,巧妙地结合了线段树的标记永久化与标记下传,在不考虑精度误差的影响下,打法应该是这样的. #in ...
- bzoj 3165: [Heoi2013]Segment 线段树
题目: Description 要求在平面直角坐标系下维护两个操作: 在平面上加入一条线段.记第i条被插入的线段的标号为i. 给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号. ...
- BZOJ 3165 李超线段树
思路: 李超线段树 我是把线段转成斜率的形式搞得 不知道有没有更简单的方法 //By SiriusRen #include <cmath> #include <cstdio> ...
随机推荐
- Git其他的命令------(四)
git除了在工作当中可以进行对代码进行管理的设置之外,git的其他指令也偶尔会被用到~ 1:删除某一个文件: rm -rf node,然后按下tab 2:查看修改文件的修改的详细信息: git ...
- Knockout双向绑定
knockout双工绑定基于 observe 模式,性能高.核心就是observable对象的定义.这个函数最后返回了一个也叫做 observable 的函数,也就是用户定义值的读写器(accesso ...
- ubuntu10.04 svn安装方法
ubuntu10.04 svn安装方法:sudo apt-get install subversion sudo apt-get install libneon27-dev orsudo apt-ge ...
- C#调用mciSendString播放音频文件
mciSendString函数是一个WinAPI,主要用来向MCI(Media Control Interface)设备发送字符串命令. 一.函数的声明如下: private static exter ...
- socket.io插件调用的demo
1.利用socket.io插件制作一个聊天框,原理是输入对话,发送到服务,服务器在返回相应的对话,最后插入页面中,时间对话的功能,这里我是使用的node.js搭建的服务器. 附上源码 <!DOC ...
- HDFS RAID实现方案(转)
原文链接:http://blog.chinaunix.net/uid-20196318-id-3213700.html 分布式文件系统主要用于解决海量数据存储的问题,如Goolge.Facebook等 ...
- 用socket发送匿名邮件之python实现
发送邮件可以用smtp协议,整个过程为: 用户代理(user-agent,比如outlook.foxmail等邮件客户端)---(smtp协议)--->本地邮件服务器 --- (smtp协议)- ...
- css3 图标变大变小在变小变大
css3 @-webkit-keyframes anLoca { from { -webkit-transform: scale3d(1, 1, 1); } to { -webkit-transfor ...
- Android项目包命名规则是怎样的?
com.example.app.activity | Activity 类com.example.app.widget | 自定义的小UIcom.example.app.db | 数据库相关操作com ...
- yii2 GirdView使用全教程
开始GridView GridView主要是为了实现表格复用,尤其我们做后台的时候,你发现表单和表格占据了大部分页面,而表格的样式又是高度的统一,那么如果有这样一个挂件,传入数据集自动渲染表格该多好. ...