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

洛谷傳送門

BZOJ傳送門

題目描述

要求在平面直角座標系下維護兩個操作:

  1. 在平面上加入一條線段。記第 ii 條被插入的線段的標號爲 ii
  2. 給定一個數 kk,詢問與直線 x=kx = k 相交的線段中,交點最靠上的線段的編號。

輸入輸出格式

輸入格式:

第一行一個整數 nn,表示共 nn 個操作

接下來 nn 行,每行第一個數爲 0011

若該數爲 00,則後面跟着一個正整數 kk,表示詢問與直線 x=((k+lastans1)%39989+1)x = ((k + lastans – 1)\%39989+1)相交的線段中交點(包括在端點相交的情形)最靠上的線段的編號,其中%表示取餘。若某條線段爲直線的一部分,則視作直線與線段交於該線段 y 座標最大處。若有多條線段符合要求,輸出編號最小的線段的編號

若該數爲 11,則後面跟着四個正整數 x0,y0,x1,y1x_0, y_0, x_1, y_1,表示插入一條兩個端點爲 ((x0+lastans1)((x_0+lastans-1)%39989+1,(y_0+lastans-1)%10^9+1)((x1+lastans1)((x_1+lastans-1)%39989+1,(y_1+lastans-1)%10^9+1) 的線段

其中 lastanslastans 爲上一次詢問的答案。初始時 lastans=0lastans=0

輸出格式:

對於每個 00 操作,輸出一行,包含一個正整數,表示交點最靠上的線段的編 號。若不存在與直線相交的線段,答案爲00

輸入輸出樣例

輸入樣例#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\%的數據,n1000n ≤ 1000
對於 100%100\%的數據,1n105,1k,x0,x139989,1y0y11091 ≤ n ≤ 10^5, 1 ≤ k, x_0, x_1 ≤ 39989, 1 ≤ y_0 ≤ y_1 ≤ 10^9

解題分析

李超線段樹板題。

對於一個區間[l,r][l,r], 我們維護在midmid位置最高的那條線段。

更新時如果在[l,r][l,r]新加入的線段比原來的線段更劣或更優, 就直接覆蓋或return。

否則留下中間更高的那個線段, 然後將更低的那條較高的一端下放更新。

這樣每條線段會對應log(N)log(N)個區間, 下放的複雜度是log(N)log(N), 所以總複雜度O(nlog2(n))O(nlog^2(n))

注意有平行於yy軸的線段, 這種情況直接將函數表達式改成最高的那個點。

代碼如下:

#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--;
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章