[Luogu P4097] [BZOJ 3165] [HEOI2013]Segment

洛谷传送门
BZOJ传送门

题目描述

要求在平面直角坐标系下维护两个操作:

  1. 在平面上加入一条线段。记第 i i i 条被插入的线段的标号为 i i i
  2. 给定一个数 k k k,询问与直线 x = k x = k x=k 相交的线段中,交点最靠上的线段的编号。

输入输出格式

输入格式:

第一行一个整数 n n n,表示共 n n n 个操作

接下来 n n n 行,每行第一个数为 0 0 0 1 1 1

若该数为 0 0 0,则后面跟着一个正整数 k k k,表示询问与直线 x = ( ( k + l a s t a n s – 1 ) % 39989 + 1 ) x = ((k + lastans – 1)\%39989+1) x=((k+lastans1)%39989+1)相交的线段中交点(包括在端点相交的情形)最靠上的线段的编号,其中%表示取余。若某条线段为直线的一部分,则视作直线与线段交于该线段 y 坐标最大处。若有多条线段符合要求,输出编号最小的线段的编号

若该数为 1 1 1,则后面跟着四个正整数 x 0 , y 0 , x 1 , y 1 x_0, y_0, x_1, y_1 x0,y0,x1,y1,表示插入一条两个端点为 ( ( x 0 + l a s t a n s − 1 ) ((x_0+lastans-1)%39989+1,(y_0+lastans-1)%10^9+1) ((x0+lastans1) ( ( x 1 + l a s t a n s − 1 ) ((x_1+lastans-1)%39989+1,(y_1+lastans-1)%10^9+1) ((x1+lastans1) 的线段

其中 l a s t a n s lastans lastans 为上一次询问的答案。初始时 l a s t a n s = 0 lastans=0 lastans=0

输出格式:

对于每个 0 0 0 操作,输出一行,包含一个正整数,表示交点最靠上的线段的编 号。若不存在与直线相交的线段,答案为 0 0 0

输入输出样例

输入样例#1:
6 
1 8 5 10 8 
1 6 7 2 6 
0 2 
0 9 
1 4 7 6 7 
0 5
输出样例#1:
2 
0 
3

说明

对于 30 % 30\% 30%的数据, n ≤ 1000 n ≤ 1000 n1000
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 1 0 5 , 1 ≤ k , x 0 , x 1 ≤ 39989 , 1 ≤ y 0 ≤ y 1 ≤ 1 0 9 1 ≤ n ≤ 10^5, 1 ≤ k, x_0, x_1 ≤ 39989, 1 ≤ y_0 ≤ y_1 ≤ 10^9 1n105,1k,x0,x139989,1y0y1109

解题分析

李超线段树板题。

对于一个区间 [ l , r ] [l,r] [l,r], 我们维护在 m i d mid mid位置最高的那条线段。

更新时如果在 [ l , r ] [l,r] [l,r]新加入的线段比原来的线段更劣或更优, 就直接覆盖或return。

否则留下中间更高的那个线段, 然后将更低的那条较高的一端下放更新。

这样每条线段会对应 l o g ( N ) log(N) log(N)个区间, 下放的复杂度是 l o g ( N ) log(N) log(N), 所以总复杂度 O ( n l o g 2 ( n ) ) O(nlog^2(n)) O(nlog2(n))

注意有平行于 y y y轴的线段, 这种情况直接将函数表达式改成最高的那个点。

代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define db double
#define ls (now << 1)
#define rs (now << 1 | 1)
#define MX 100500
#define MOD 1000000000
#define EPS 1e-8
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
int n, lastans = -1, tot;
struct Node {int id; bool use;} tree[MX << 1];
struct Line {db k, b;} line[MX];
IN db f(R int id, R int x) {return line[id].k * x + line[id].b;}
IN bool better(R int x, R int y, R int pos)
{
	db fx = f(x, pos), fy = f(y, pos);
	if (abs(fx - fy) < EPS) return x < y;
	else return fx > fy;
}
void insert(R int now, R int lef, R int rig, R int lb, R int rb, R int id)
{
	if (rb < lef || lb > rig) return;
	int mid = lef + rig >> 1;
	if (lb <= lef && rb >= rig)
	{
		if (better(id, tree[now].id, lef) && better(id, tree[now].id, rig))
		return tree[now].id = id, void();
		if (better(tree[now].id, id, lef) && better(tree[now].id, id, rig))
		return;
		if (better(id, tree[now].id, mid)) std::swap(tree[now].id, id);
		if (better(id, tree[now].id, lef)) insert(ls, lef, mid, lef, rig, id);
		else insert(rs, mid + 1, rig, lef, rig, id);
		return;
	}
	insert(ls, lef, mid, lb, rb, id);
	insert(rs, mid + 1, rig, lb, rb, id);
}
int query(R int now, R int lef, R int rig, R int tar)
{
	if (lef == rig) return tree[now].id;
	int mid = lef + rig >> 1, ret;
	if (tar <= mid)
	{
		ret = query(ls, lef, mid, tar);
		return better(ret, tree[now].id, tar) ? ret : tree[now].id;
	}
	else
	{
		ret = query(rs, mid + 1, rig, tar);
		return better(ret, tree[now].id, tar) ? ret : tree[now].id;
	}
}
int main(void)
{
	in(n);
	int lx, ly, rx, ry, typ, pos;
	for (R int i = 1; i <= n; ++i)
	{
		in(typ);
		if (typ & 1)
		{
			in(lx), in(ly), in(rx), in(ry);
			lx = (lx + lastans + 39989) % 39989 + 1;
			ly = (ly + lastans + MOD) % MOD + 1;
			rx = (rx + lastans + 39989) % 39989 + 1;
			ry = (ry + lastans + MOD) % MOD + 1;
			++tot;
			if (lx > rx) std::swap(lx, rx), std::swap(ly, ry);
			if (lx == rx) line[tot] = {0, max(ly, ry)};
			else line[tot].k = 1.0 * (ry - ly) / (rx - lx), line[tot].b = ly - lx * line[tot].k;
			insert(1, 1, 40000, lx, rx, tot);
		}
		else
		{
			in(pos);
			pos = (pos + lastans + 39989) % 39989 + 1;
			lastans = query(1, 1, 40000, pos);
			printf("%d\n", lastans);
			lastans--;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值