luogu P4097 [HEOI2013]Segment

李超线段树模板题。

大概思路呢,就是每个区间留着一个标记\(tag\)表示在这个区间中点函数值最大线段的编号,然后在不停的放线段进去递归处理就行了。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=100009,M=40000;
int n,Q;
struct LC_Tree
{
	int Max[M*4],cnt;
	double K[N],B[N];
	
	double val(int id,int x)
	{
		return x*K[id]+B[id];
	}
	void Ins(int x,int y,int X,int Y)
	{
		cnt++;
		K[cnt]=1.*(Y-y)/(X-x);
		B[cnt]=Y-K[cnt]*X;
	}
	void Modify(int k,int l,int r,int id)
	{
		if(l==r)
		{
			Max[k]=val(Max[k],l)>val(id,l)?Max[k]:id;
			return;
		}
		int mid=l+r>>1;
		if(K[id]>K[Max[k]])
		{
			if(val(id,mid)>val(Max[k],mid))
				Modify(k<<1,l,mid,Max[k]),Max[k]=id;
			else
				Modify(k<<1|1,mid+1,r,id);
		}
		else
		{
			if(val(id,mid)>val(Max[k],mid))
				Modify(k<<1|1,mid+1,r,Max[k]),Max[k]=id;
			else
				Modify(k<<1,l,mid,id);
		}
	}
	void change(int k,int l,int r,int x,int y,int id)
	{
		if(l>=x&&r<=y)
		{
			Modify(k,l,r,id);
			return;
		}
		int mid=l+r>>1;
		if(mid>=x)
			change(k<<1,l,mid,x,y,id);
		if(mid<y)
			change(k<<1|1,mid+1,r,x,y,id);
	}
	double Query(int k,int l,int r,int x)
	{
		if(l==r)
			return Max[k];
		int mid=l+r>>1,qwq;
		double ans=Max[k];
		if(mid>=x)
			ans=val(qwq=Query(k<<1,l,mid,x),x)>val(ans,x)?qwq:ans;
		else
			ans=val(qwq=Query(k<<1|1,mid+1,r,x),x)>val(ans,x)?qwq:ans;
		return ans;
	}
}A;

void init()
{
	scanf("%d",&n);
}

void work()
{
	int last=0,opt,x,y,X,Y;
	for (int _=1;_<=n;_++)
	{
		scanf("%d",&opt);
		if(opt==0)
		{
			scanf("%d",&x);
			x=(x+last-1)%39989+1;
			printf("%d\n",last=A.Query(1,1,M,x));
		}
		else
		{
			scanf("%d %d %d %d",&x,&y,&X,&Y);
			x=(x+last-1)%39989+1,y=(y+last-1)%1000000000+1;
			X=(X+last-1)%39989+1,Y=(Y+last-1)%1000000000+1;
			if(x>X)
				swap(x,X),swap(y,Y);
			A.Ins(x,y,X,Y);
			A.change(1,1,M,x,X,A.cnt);
		}
	}
}

int main()
{
	init();
	work();
	return 0;
}
posted @ 2020-04-22 22:32  With_penguin  阅读(113)  评论(0编辑  收藏  举报