P4097 [HEOI2013]Segment

题目链接

P4097 [HEOI2013]Segment

题目描述

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

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

输入格式

本题输入强制在线

输入的第一行是一个整数 \(n\),代表操作的个数。

接下来 \(n\) 行,每行若干个用空格隔开的整数,第 \((i + 1)\) 行的第一个整数为 \(op\),代表第 \(i\) 次操作的类型。

\(op = 0\),则后跟一个整数 \(k\),代表本次操作为查询所所有与直线 \(x = (k + lastans - 1) \bmod 39989 + 1\) 相交的线段中,交点纵坐标最大的线段编号。

\(op = 1\),则后跟四个整数 \(x_0, y_0, x_1, y_1\),记 \(x_i' = (x_i + lastans - 1) \bmod 39989 + 1\)\(y_i' = (y_i + lastans - 1) \bmod 10^9 + 1\)。本次操作为插入一条两端点分别为 \((x_0', y_0')\)\((x_1',y_1')\) 的线段。

其中 \(lastans\) 为上次询问的答案,初始时,\(lastans = 0\)

输出格式

对于每次查询,输出一行一个整数,代表交点纵坐标最大的线段的编号。若不存在任何一条线段与查询直线有交,则输出 \(0\);若有多条线段与查询直线的交点纵坐标都是最大的,则输出编号最小的线段,同时 \(lastans\) 也应更新为编号最小的一条线段。

样例 #1

样例输入 #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

提示

样例输入输出 \(1\) 解释

对于第一次操作,解密后为 1 8 5 10 8

对于第二次操作,解密后为 1 6 7 2 6

对于第三次操作,解密后为 0 2,此时 \(lastans\) 被更新为 \(2\)

对于第四次操作,解密后为 0 11,此时 \(lastans\) 被更新为 \(0\)

对于第五次操作,解密后为 1 4 7 6 7

对于第六次操作,解密后为 0 5

数据范围与约定

对于 \(30\%\) 的数据,保证 \(n \leq 10^3\)

对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 10^5\)\(1 \leq k, x_0, x_1 \leq 39989\)\(1 \leq y_0, y_1 \leq 10^9\)

提示

不保证 \(x_0 \neq x_1\)。对于一条 \(x_0' = x_1'\) 的线段,认为其与 \(x = x_0'\) 的交点为其两端点中纵坐标较大的端点。

解题思路

李超线段树

李超线段树的主要用途:插入线段,查询单点极值
用线段树维护 \(x\) 轴,每个区间节点 \([l,r]\) 保存 \(x\)\(mid=\frac{l+r}{2}\) 的最优 \(y\) 的线段编号,对于一个新来的线段 \(line\),设线段 \(line\)\(x\) 范围为 \([l,r]\),则该线段只会对被该区间包含的线段树节点区间有影响,即先找到被影响的线段树节点,如果当前线段树中没有保存编号,则直接将该节点作为整个线段树的初始最优编号,否则将线段 \(line\) 跟线段树中保存的线段 \(line'\) 进行比较,如果对于节点区间中心 \(mid\) 来说 \(line\) 要更优则当前线段树节点保存 \(line\) 这条线段,假设 \(line\) 要比 \(line'\) 更劣,如果对于节点区间左端点来说,新线段 \(line\) 要比 \(line'\) 更优,则说明左子树表示的区间有部分区间不如 \(line\) 优,往左子树递归,右端点同理,查询单点极值暴力查询即可

  • 时间复杂度:\(O(mlogn)\)

代码

// Problem: P4097 [HEOI2013]Segment
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4097
// Memory Limit: 128 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

typedef pair<double,int> PDI;
const int N=40005,M=1e5+5,mod1=39989,mod2=1e9;
const double eps=1e-8;
int n;

struct Line
{
	double k,b;
}line[M];
struct Tr
{
	int l,r,id;
}tr[N<<2];
void build(int p,int l,int r)
{
	tr[p]={l,r};
	if(l==r)
		return ;
	int mid=l+r>>1;
	build(p<<1,l,mid),build(p<<1|1,mid+1,r);
}
double get(int id,int x)
{
	return line[id].k*x+line[id].b;
}
int cmp(double a,double b)
{
	if(a-b>eps)return 1;
	if(b-a>eps)return -1;
	return 0;
}
void update(int p,int l,int r,int id)
{
	if(l<=tr[p].l&&tr[p].r<=r)
	{
		if(!tr[p].id)tr[p].id=id;
		else
		{
			int &tid=tr[p].id;
			int mid=tr[p].l+tr[p].r>>1;
			double new_y=get(id,mid),old_y=get(tid,mid);
			if(cmp(new_y,old_y)==1)swap(tid,id);
			if(tr[p].l==tr[p].r)return ;
			int judgel=cmp(get(id,l),get(tid,l));
			int judger=cmp(get(id,r),get(tid,r));
			if(judgel==1||(!judgel&&id<tid))update(p<<1,l,r,id);
			if(judger==1||(!judger&&id<tid))update(p<<1|1,l,r,id);
		}
		return ;
	}
	int mid=tr[p].l+tr[p].r>>1;
	if(l<=mid)update(p<<1,l,r,id);
	if(r>mid)update(p<<1|1,l,r,id);
}
PDI MAX(PDI a,PDI b)
{
	if(cmp(a.fi,b.fi)==1)return a;
	else if(cmp(a.fi,b.fi)==-1)return b;
	return a.se<b.se?a:b;
}
PDI ask(int p,int x)
{
	if(x<tr[p].l||x>tr[p].r)return {0,0};
    PDI res={get(tr[p].id,x),tr[p].id};
    if(tr[p].l==tr[p].r)return res;
    res=MAX(res,ask(p<<1,x));
    res=MAX(res,ask(p<<1|1,x));
    return res;
}
int main()
{
	build(1,1,40000);
	int lstans=0,cnt;
	int t=0;
    for(scanf("%d",&n);n;n--)
    {
    	int x0,y0,x1,y1,k,op;
    	scanf("%d",&op);
    	if(op)
    	{
    		scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
    		x0=(x0+lstans-1)%mod1+1,x1=(x1+lstans-1)%mod1+1;
    		y0=(y0+lstans-1)%mod2+1,y1=(y1+lstans-1)%mod2+1;
    		if(x0>x1)swap(x0,x1),swap(y0,y1);
    		if(x0==x1)line[++cnt]={0,(double)max(y0,y1)};
    		else
    			line[++cnt]={(double)(y1-y0)/(x1-x0),y1-(double)(y1-y0)/(x1-x0)*x1};
    		update(1,x0,x1,cnt);
    	}
    	else
    	{
    		scanf("%d",&k);
    		k=(k+lstans-1)%mod1+1;
    		printf("%d\n",lstans=ask(1,k).se);
    	}
    	
    }
    return 0;
}
posted @ 2022-10-20 22:00  zyy2001  阅读(17)  评论(0编辑  收藏  举报