[HEOI2013]Segment

题目

为了证明我学过李超树,我还是来写这篇博客吧

李超树支持区间插入一条直线,询问区间或单点的最大值,主要运用了标记永久化的思想

对于线段树上每一个节点维护一个标记,记录在这个区间中点(mid)上值最大的直线

对于插入操作,如果我们插入的直线在(mid)上值更大,我们就把要插入的直线和标记直线swap一下

swap之后要插入的直线在(mid)上一定比标记直线低了,我们再来比较一下斜率;如果待插入直线的斜率更大,那么说明在左区间里,这条直线都是小于标记直线的,我们向右区间插入;否则,就向左区间插入

不难发现这样的全局插入是(O(log n))的,算上区间定位的复杂度是(O(log^2n))

查询单点最值的时候暴力往上跳即可,是(O(log n))的;查询区间最值得时候需要维护每个点的最大值

代码

#include<bits/stdc++.h>
#define re register
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const double eps=1e-8;const int mod=1e9+1;const int maxn=39989;
struct SEG{double k,b;}seg[100005];
int pos[maxn+1],l[maxn<<2],r[maxn<<2],tag[maxn<<2],lst,cnt,w[maxn],id[maxn];
inline int trans() {return (read()+lst-1)%maxn+1;}
inline int transP() {return (read()+lst-1)%mod+1;}
inline int cmp(int A,int B,int x) {
	double fA=seg[A].k*(double)x+seg[A].b,fB=seg[B].k*(double)x+seg[B].b;
	return (fA+eps>fB&&fA-eps<fB)?(A<B):(fA>fB);
}
void ins(int i,int &t) {
	int mid=l[i]+r[i]>>1;
	if(cmp(t,tag[i],mid))std::swap(t,tag[i]);
	if(l[i]==r[i]) return;
	seg[t].k<seg[tag[i]].k?ins(i<<1,t):ins(i<<1|1,t);
}
void build(int x,int y,int i) {
	l[i]=x,r[i]=y;if(x==y) {pos[x]=i;return;}
	int mid=x+y>>1;build(x,mid,i<<1),build(mid+1,y,i<<1|1);
}
void fid_Seg(int x,int y,int i,int t) {
	if(x<=l[i]&&y>=r[i]) {ins(i,t);return;}
	int mid=l[i]+r[i]>>1;
	if(x<=mid) fid_Seg(x,y,i<<1,t);
	if(y>mid) fid_Seg(x,y,i<<1|1,t); 
} 
inline int qry(int x) {
	int h=0,t=x;x=pos[x];
	while(x) {if(cmp(tag[x],h,t)) h=tag[x];x>>=1;}
	return h;
}
int main() {
	build(1,maxn,1);
	for(re int op,T=read(),x,y,xx,yy;T;--T) {
		op=read();
		if(op) {
			++cnt;x=trans(),y=transP(),xx=trans(),yy=transP();
			if(x>xx)std::swap(x,xx),std::swap(y,yy);
			if(x==xx) {
				if(yy>y) y=yy;if(y>w[x]) w[x]=y,id[x]=cnt;
				continue;
			}
			seg[cnt].k=(double)(yy-y)/(xx-x);
			seg[cnt].b=(double)(y+yy-seg[cnt].k*(x+xx))/2.0;
			fid_Seg(x,xx,1,cnt);
		}
		else {
			x=trans();int nw=qry(x);
			double fnw=seg[nw].k*(double)x+seg[nw].b;
			if(fnw+eps>w[x]&&fnw+eps<w[x]) lst=(nw<id[x]?nw:id[x]);
			else lst=(fnw>w[x]?nw:id[x]);
			printf("%d
",lst);
		}
	}
}
原文地址:https://www.cnblogs.com/asuldb/p/12154953.html