李超线段树
李超线段树
例1:HEOI segment
食用下面两个博客
https://www.cnblogs.com/Wendigo/p/12694123.html
https://www.luogu.com.cn/blog/fzber0103/Li-Chao-Tree
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define ls (p<<1)
#define rs (p<<1|1)
#define db double
const int N=400010;
const int mod=39989;
const int MOD=1e9;
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return x;
}
struct TREE{
int id;
db k,b;
TREE(){}
TREE(int x1,int y1,int x2,int y2,int x){id=x;k=db(y1-y2)/(x1-x2);b=y1-x1*k;}
}a[N],t[N];
int n,ans,x,z,tot;
inline db Y(TREE c,int x){
return c.k*x+c.b;
}
void modify(int l,int r,int L,int R,TREE x,int p){//保留优势最大的线段
int mid=(l+r)>>1;
if(L<=l&&r<=R){
if(!t[p].id || Y(t[p],mid)<Y(x,mid)) swap(t[p],x);//x要大的
if(l==r || t[p].k==x.k ||!x.id) return;//显然这不用管
double jiao=(t[p].b-x.b)/(x.k-t[p].k);//求交点横坐标
if(jiao<(db)l||jiao>(db)r) return;//交点在外面
if(x.k<t[p].k) modify(l,mid,L,R,x,ls);//交点在左区间
if(x.k>t[p].k) modify(mid+1,r,L,R,x,rs);//交点在右区间
}else{
if(L<=mid) modify(l,mid,L,R,x,ls);
if(R>mid) modify(mid+1,r,L,R,x,rs);
}
}
TREE query(int l,int r,int x,int p){
if(l==r) return t[p];
int mid=(l+r)>>1;
TREE now;
if(x<=mid) now=query(l,mid,x,ls);
if(x>mid) now=query(mid+1,r,x,rs);
return (!now.id||Y(now,x)<Y(t[p],x))?t[p]:now;
}
int main(){
n=read();
for(int i=1,op,x1,x2,y1,y2;i<=n;i++){
op=read();
if(op==0){
z=read();
x=(z+ans-1)%mod+1;
ans=query(1,mod,x,1).id;
printf("%d\n",ans);
}else{
x1=(read()+ans-1)%mod+1;y1=(read()+ans-1)%MOD+1;x2=(read()+ans-1)%mod+1;y2=(read()+ans-1)%MOD+1;
tot++;
if(x1==x2){
a[tot].k=0;a[tot].b=max(y1,y2);a[tot].id=tot;
modify(1,mod,x1,x2,a[tot],1);
continue;
}
if(x1>x2)swap(x1,x2),swap(y1,y2);
a[tot]=TREE(x1,y1,x2,y2,tot);
modify(1,mod,x1,x2,a[tot],1);
}
}
return 0;
}
例2:Blue Mary开公司
Description
P[i] = k
总体思路类似,但代码不同,具体见下面
对于modify 修改整个区间(1,M),原则是让 tag[p] 的 y 大
分类讨论即可
if(l==r){
if(Y(tag[p],l)<Y(x,l)) tag[p]=x;
return;
}
if(!tag[p]) {tag[p]=x;return;}
else{
int mid=(l+r)>>1;
double y1=Y(tag[p],mid),y2=Y(x,mid);
if(k[tag[p]]<k[x]){
if(y1<=y2) {modify(l,mid,tag[p],ls);tag[p]=x;}
else modify(mid+1,r,x,rs);
}else if(k[tag[p]]>k[x]){
if(y1<=y2) {modify(mid+1,r,tag[p],rs);tag[p]=x;}
else modify(l,mid,x,ls);
}else if(b[tag[p]]<b[x]){
tag[p]=x;
}
}
#include <iostream>
#include <cstdio>
using namespace std;
#define ls (p<<1)
#define rs (p<<1|1)
const int N=4000010;
const int M=500005;
double k[N],b[N];
int n,ans;
int tag[N];
inline double Y(int i,int x){
return k[i]*(x-1)+b[i];
}
void modify(int l,int r,int x,int p){//留大的
if(l==r){
if(Y(tag[p],l)<Y(x,l)) tag[p]=x;
return;
}
if(!tag[p]) {tag[p]=x;return;}
else{
int mid=(l+r)>>1;
double y1=Y(tag[p],mid),y2=Y(x,mid);
if(k[tag[p]]<k[x]){
if(y1<=y2) {modify(l,mid,tag[p],ls);tag[p]=x;}
else modify(mid+1,r,x,rs);
}else if(k[tag[p]]>k[x]){
if(y1<=y2) {modify(mid+1,r,tag[p],rs);tag[p]=x;}
else modify(l,mid,x,ls);
}else if(b[tag[p]]<b[x]){
tag[p]=x;
}
}
}
double query(int l,int r,int x,int p){
if(l==r) return Y(tag[p],l);
double res=Y(tag[p],x);
int mid=(l+r)>>1;
if(x<=mid) res=max(res,query(l,mid,x,ls));
if(x>mid) res=max(res,query(mid+1,r,x,rs));
return res;
}
char op[15];
int tot;
int main(){
scanf("%d",&n);
for(int i=1,t;i<=n;i++){
scanf("%s",op+1);
if(op[1]=='Q'){
scanf("%d",&t);
if(tot==0) printf("0\n");
else printf("%d\n",(int)query(1,M,t,1)/100);
}else{
tot++;
scanf("%lf%lf",&b[tot],&k[tot]);
modify(1,M,tot,1);
}
}
return 0;
}