李超线段树

李超线段树

例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;
}

例3:[SDOI2016]游戏

https://www.luogu.com.cn/problem/P4069

https://www.luogu.com.cn/problem/P4655

posted @ 2020-08-14 00:24  ke_xin  阅读(40)  评论(0编辑  收藏  举报