BZOJ3165: [Heoi2013]Segment

3165: [Heoi2013]Segment

Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 939 Solved: 387
[Submit][Status][Discuss]

Description

要求在平面直角坐标系下维护两个操作:
1.在平面上加入一条线段。记第i条被插入的线段的标号为i。
2.给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。

Input

第一行一个整数n,表示共n 个操作。
接下来n行,每行第一个数为0或1。

若该数为 0,则后面跟着一个正整数 k,表示询问与直线
x = ((k +lastans–1)%39989+1)相交的线段中交点(包括在端点相交的情形)最靠上的线段的编号,其中%表示取余。若某条线段为直线的一部分,则视作直线与线段交于该线段y坐标最大处。若有多条线段符合要求,输出编号最小的线段的编号。
若该数为 1,则后面跟着四个正整数 x0, y0, x 1, y 1,表示插入一条两个端点为
((x0+lastans-1)%39989+1,(y0+lastans-1)%10^9+1)和((x
1+lastans-1)%39989+1,(y1+lastans-1)%10^9+1) 的线段。
其中lastans为上一次询问的答案。初始时lastans=0。

Output

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

Sample Input

6

1 8 5 10 8

1 6 7 2 6

0 2

0 9

1 4 7 6 7

0 5

Sample Output

2

0 3

HINT

对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。

Source

题解

李超线段树模板题。

李超线段树的思想大概是这样,每个节点都保留一个能够覆盖这个区间的线段,保证这个线段与区间内任何一个线段比较,都至少一半高于区间内的线段

对于新来的线段,如果线段包含区间,如果全部高于/低于区间内线段,就覆盖/不覆盖,否则按照交点分类递归下去。
如果交点在左边,那就递归左边,
交点在右边,就递归右边。
最多\(\log n\)
至于当前节点保留原线段还是新来的线段,按照“保证这个线段与区间内任何一个线段比较,都至少一半高于区间内的线段”规则判断。

线段不包含区间那就像普通sgt一样递归即可,最多\(\log n\)
复杂度\(O(n\log ^1 n)\)

注意线段垂直于x轴时,看做一个点即可。

要求输出编号最小的,通过修改和查询双重保证编号最小

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#define Pair std::pair<double, int>
inline void swap(int &x, int &y){int tmp = x;x = y;y = tmp;}
inline void read(int &x)
{
    x = 0;char ch = getchar(), c = ch;
    while(ch < '0' || ch > '9') c = ch, ch = getchar();
    while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
    if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 100000 + 10;
int max(int a, int b){return a > b ? a : b;}
double max(double a, double b){return a > b ? a : b;}
struct Line
{
	double k, b;
	int l, r, rank;
	Line()
	{
		l = 1, r = 40000;
		rank = k = b = 0;
	}
	Line(int x1, int y1, int x2, int y2, int _rank)
	{
		rank = _rank;
		if(x1 > x2) swap(x1, x2), swap(y1, y2);
		l = x1, r = x2;
		if(x1 == x2)
		{
			k = 0;
			b = max(y1, y2);	
		}
		else
		{
			k = ((double)y1 - y2) / (x1 - x2);
			b = (double)y1 - x1 * k;
		}
	}
	double f(int x)
	{
		return k * x + b;
	}
};
struct Node
{
	int l, r;
	Line line;
}node[MAXN << 2];
void build(int o = 1, int l = 1, int r = 40000)
{
	node[o].l = l, node[o].r = r;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(o << 1, l, mid);
	build(o << 1 | 1, mid + 1, r);
}
void modify(Line L, int o = 1)
{
	if(L.l <= node[o].l && node[o].r <= L.r)
	{
		if(L.f(node[o].l) <= node[o].line.f(node[o].l) &&
			L.f(node[o].r) <= node[o].line.f(node[o].r)) return;
		if(L.f(node[o].l) > node[o].line.f(node[o].l) &&
			L.f(node[o].r) > node[o].line.f(node[o].r)) 
			{
				node[o].line = L;return;
			}
		double x = (node[o].line.b - L.b) / (L.k - node[o].line.k);
		int mid = (node[o].l + node[o].r) >> 1;
		if(x < mid)
		{
			if(L.f(node[o].r) > node[o].line.f(node[o].r))
				modify(node[o].line, o << 1), node[o].line = L;
			else modify(L, o << 1);
		}
		else
		{
			if(L.f(node[o].l) > node[o].line.f(node[o].l))
				modify(node[o].line, o << 1 | 1), node[o].line = L;
			else modify(L, o << 1 | 1);
		}
		return;
	}
	int mid = (node[o].l + node[o].r) >> 1;
	if(L.l <= mid) modify(L, o << 1);
	if(L.r > mid) modify(L, o << 1 | 1);
}
Pair max(Pair a, Pair b)
{
	return a.first == b.first ? (b.second < a.second ? b : a) : (a.first < b.first ? b : a);
}
Pair ask(int pos, int o = 1)
{
	if(node[o].l == node[o].r)
		return std::make_pair(node[o].line.f(pos), node[o].line.rank);
	Pair re = std::make_pair(node[o].line.f(pos), node[o].line.rank);
	int mid = (node[o].l + node[o].r) >> 1;
	if(pos <= mid) re = max(re, ask(pos, o << 1));
	else re = max(re, ask(pos, o << 1 | 1));
	return re;
}
int tot;
int main()
{
	int lastans = 0, n;
	read(n);
	build();
	for(int i = 1;i <= n;++ i)
	{
		int tmp;read(tmp);
		if(tmp)
		{
			int tmp1, tmp2, tmp3, tmp4;
			read(tmp1), read(tmp2), read(tmp3), read(tmp4);
			tmp1 = (tmp1 + lastans - 1) % 39989 + 1;
			tmp2 = (tmp2 + lastans - 1) % 1000000000 + 1;
			tmp3 = (tmp3 + lastans - 1) % 39989 + 1;
			tmp4 = (tmp4 + lastans - 1) % 1000000000 + 1;
			modify(Line(tmp1, tmp2, tmp3, tmp4, ++ tot));
		}
		else
		{
			read(tmp);
			tmp = (tmp + lastans - 1) % 39989 + 1;
			printf("%d\n", lastans = ask(tmp).second);
		}
	}
    return 0;
}
posted @ 2018-03-15 16:06  嘒彼小星  阅读(244)  评论(0编辑  收藏  举报