为了证明我学过李超树,我还是来写这篇博客吧
李超树支持区间插入一条直线,询问区间或单点的最大值,主要运用了标记永久化的思想
对于线段树上每一个节点维护一个标记,记录在这个区间中点(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);
}
}
}