zoukankan      html  css  js  c++  java
  • 李超线段树

    功能

    李超线段树资瓷以下两种操作:

    1.在二维平面内插入一条线段
    2.询问与直线(x=K)相交的线段中,交点纵坐标最大为多少。

    原理

    结点

    李超线段树的每个节点,都维护这一个优势线段。这个优势线段使得该节点所维护区间的中点在该优势线段上最大。

    修改

    考虑如何维护上面的结点呢。
    分三种情况讨论:
    1.该区间无优势线段或要插入的线段在该区间内完全在优势线段之上,将该区间的优势线段记为该线段并返回。
    2.要插入的线段完全被之前的优势线段覆盖。直接返回
    3.否则下放到左右两个子区间。

    查询

    从根节点走到查询位置的叶子结点。对路径上所有结点的优势节点在查询位置的(y)取最大值即可。

    时间复杂度

    查询一次的时间复杂度显然为(log(n))

    修改时,每个线段最多被分为(log(n))段。每段最多被下放(log(n))次。所以修改一次的最坏复杂度为(log^2(n))

    代码

    luogu4097

    /*
    * @Author: wxyww
    * @Date:   2019-07-17 08:32:42
    * @Last Modified time: 2019-07-17 10:00:19
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 100000 + 100,mod = 39989,mod2 = 1e9;
    const double aps = 1e-8;
    ll read() {
    	ll x=0,f=1;char c=getchar();
    	while(c<'0'||c>'9') {
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9') {
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x*f;
    }
    
    struct node {
    	double k,b;
    	node() {}
    	node(int x1,int x2,int y1,int y2) {
    		if(x1 == x2) {
    			k = 0;b = max(y1,y2);
    			return;
    		}
    		k = 1.0 * (y2 - y1) / (x2 - x1);
    		b = y2 - k * x2;
    	}
    	double calc(int x) {
    		return k * x + b;
    	}
    }a[N];
    int tree[N << 2];
    void update(int rt,int l,int r,int L,int R,int x) {
    	if(L <= l && R >= r) {
    		if(!tree[rt]) {
    			tree[rt] = x;
    			return;
    		}
    		if(a[x].calc(r) - a[tree[rt]].calc(r) >= aps && a[x].calc(l) - a[tree[rt]].calc(l) >= aps) {
    			tree[rt] = x;
    			return;
    		}
    		if(a[tree[rt]].calc(l) - a[x].calc(l) >= aps && a[tree[rt]].calc(r) - a[x].calc(r) >= aps) return;
    		if(l == r) return;
    	}
    	int mid = (l + r) >> 1;
    	if(L <= mid) update(rt << 1,l,mid,L,R,x);
    	if(R > mid) update(rt << 1 | 1,mid + 1,r,L,R,x);
    }
    int ANS;
    void query(int rt,int l,int r,int pos) {
    	if(a[tree[rt]].calc(pos) - a[ANS].calc(pos) >= aps) ANS = tree[rt];
    	if(fabs(a[tree[rt]].calc(pos) - a[ANS].calc(pos)) <= aps && ANS > tree[rt]) ANS = tree[rt];
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	if(pos <= mid) query(rt << 1,l,mid,pos);
    	else query(rt << 1 | 1,mid + 1,r,pos);
    }
    int tot = 0;
    int main() {
    	int n = read();
    	a[0] = node(1,1,-1,-1);
    	while(n--) {
    		int opt = read();
    		if(!opt) {
    			int K = (read() + ANS - 1) % mod + 1;
    			ANS = 0;query(1,1,N - 10,K);
    			printf("%d
    ",ANS);
    		}
    		else {
    			int x1 = (read() + ANS - 1) % mod + 1,y1 = (read() + ANS - 1) % mod2 + 1,x2 = (read() + ANS - 1) % mod + 1,y2 = (read() + ANS - 1) % mod2 + 1;
    			if(x1 > x2) swap(x1,x2),swap(y1,y2);
    			a[++tot] = node(x1,x2,y1,y2);
    			update(1,1,N - 10,x1,x2,tot);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    差分序列
    蓝桥杯 操作格子
    线段树
    历届题目 密文搜索
    对局匹配(动态规划)
    历届试题 分巧克力(二分查找)
    第九届蓝桥杯B组决赛 调手表(完全背包)
    快速幂求余
    2019蓝桥杯国赛备赛题库
    ubuntu16.04安装cuda8.0试错锦集
  • 原文地址:https://www.cnblogs.com/wxyww/p/lichaotree.html
Copyright © 2011-2022 走看看