• 【瞎口胡】李超线段树


    现在有如下问题:

    要求在平面直角坐标系下在线维护两个操作:

    1. 在平面上加入一个定义域为 \([l,r]\) 的一次函数。记第 \(i\) 个被插入的一次函数标号为 \(i\)
    2. 给定一个数 \(k\),询问与直线 \(x = k\) 相交的一次函数中,交点纵坐标最大的一次函数的编号。

    如果插入的一次函数横坐标为整数,那么李超树可以用线段树的分治结构在 \(O(n \log n)\) 的时间复杂度和 \(O(n)\) 的空间复杂度内解决上面的问题。

    概述

    李超树使用了线段树的结构,按横坐标进行分治。区间 \([l,r]\) 对应节点维护的是 \(x=l\)\(x=r\) 这一段区间的优势函数。要求:

    • 该函数覆盖区间 \([l,r]\)。即:和 \(x=l\)\(x=r\) 都有交。
    • 该函数在区间中点 \(mid\) 处的取值最大。

    那么插入一个函数,会有如下几种情况发生:

    • 如果当前函数定义域没有覆盖 \([l,r]\),那么往下递归;
    • 否则,如果当前函数更优,更新当前区间的优势函数。此时被淘汰掉的函数(称为劣势函数)仍然有可能成为子区间的优势函数。
      • 如果劣势函数在 \(x=l\) 处取值比优势函数大,说明这两个函数在 \([l,mid]\) 处有交,而在 \([mid,r]\) 中,劣势函数取值严格不比优势函数大,所以不可能成为右半区间的优势函数,而左半区间有机会。此时递归左半区间。
      • 同理,如果劣势函数在 \(x=r\) 处取比优势函数大,递归右半区间。

    查询的时候,需要比较经过的所有节点的优势函数,因为上述更新过程类似于标记永久化

    例题 [HEOI2013]Segment

    题意

    同上,只不过不保证插入的是一个一次函数(可能会平行于坐标轴)。

    操作次数 \(n\) 满足 \(1 \leq n\leq 10^5\),横纵坐标范围分别为 \([1,39989],[1,10^9]\)

    题解

    注意到平行于 \(x\) 轴不影响,平行于 \(y\) 轴的线段可以勉强写成 \(y=0x+\max\{y_0,y_1\}\) 这样的形式。

    直接做就可以了。

    # include <bits/stdc++.h>
    
    const int N=40010,INF=0x3f3f3f3f,MAXN=N-10,BMAX=1e9;
    const double EPS=1e-8;
    
    struct Seg{
    	double k,b;
    	inline double fx(double x){
    		return k*x+b;
    	}
    }a[100010];
    int n,tree[N<<2],lst,cnt; // tree[x] 存节点 x 对应的优势函数编号
    
    inline int read(void){
    	int res,f=1;
    	char c;
    	while((c=getchar())<'0'||c>'9')
    		if(c=='-')f=-1;
    	res=c-48;
    	while((c=getchar())>='0'&&c<='9')
    		res=res*10+c-48;
    	return res*f;
    }
    inline int Sign(double x){
    	return (x>EPS)?1:((fabs(x)<EPS)?0:-1);
    }
    inline int lc(int x){
    	return x<<1;
    }
    inline int rc(int x){
    	return x<<1|1;
    } 
    
    void modify(int k,int l,int r,int L,int R,int q){
    	if(L<=l&&r<=R){
    		int mid=(l+r)>>1;
    		int &p=tree[k];
    		if(Sign(a[q].fx(mid)-a[p].fx(mid))==1) std::swap(p,q);
    		if(Sign(a[q].fx(l)-a[p].fx(l))==1) modify(lc(k),l,mid,L,R,q);
    		if(Sign(a[q].fx(r)-a[p].fx(r))==1) modify(rc(k),mid+1,r,L,R,q);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(L<=mid) modify(lc(k),l,mid,L,R,q);
    	if(mid<R) modify(rc(k),mid+1,r,L,R,q);
    	return;
    }
    int query(int k,int l,int r,int x){
    	if(l==r) return tree[k];
    	int mid=(l+r)>>1;
    	int res=((x<=mid)?query(lc(k),l,mid,x):query(rc(k),mid+1,r,x)),sig=Sign(a[res].fx(x)-a[tree[k]].fx(x));
    	if(!sig) return std::min(res,tree[k]);
    	return (sig==1)?res:tree[k];
    }
    inline void trans(int &x,int MOD){
    	x=(x+lst-1)%MOD+1;
    	return;
    }
    
    int main(void){
    	n=read();
    	int op,k,xa,xb,ya,yb;
    	while(n--){
    		op=read();
    		if(!op){
    			k=read(),trans(k,39989);
    			printf("%d\n",lst=query(1,1,MAXN,k));
    		}else{
    			xa=read(),ya=read(),xb=read(),yb=read();
    			trans(xa,39989),trans(xb,39989),trans(ya,BMAX),trans(yb,BMAX); // 强制在线
    			if(xa>xb) std::swap(xa,xb),std::swap(ya,yb);
    			if(xa==xb) a[++cnt].k=0,a[cnt].b=std::max(ya,yb); // 特判
    			else a[++cnt].k=(double)(ya-yb)/(double)(xa-xb),a[cnt].b=ya-xa*a[cnt].k;
    			modify(1,1,MAXN,xa,xb,cnt);
    		}
    	}
    	
    	return 0;
    }
    
    
  • 相关阅读:
    linux如何用yum进行部署xampp环境
    jmeter关联案例的几种方法
    jmeter中元件
    CentOS7在VMware下设置成桥接模式
    CentOS7使用vsftpd搭建ftp
    虚拟机WMware15和CnetOS7安装
    MySql忘记密码的解决方案
    Windows下MySql8解压版的安装与完全卸载
    Idea设置统一为utf-8编码格式
    Idea常用快捷键
  • 原文地址:https://www.cnblogs.com/liuzongxin/p/16542042.html
Copyright © 2020-2023  润新知