李超线段树(segment[HEOI2013]-洛谷T4097)

(neng了好久好久才糊弄懂得知识点...)

一、李超线段树

    在线动态维护一个二维平面直角坐标系,

    支持插入一条线段,

    询问与直线x = x0相交的所有线段中,交点y的最大/小值

    (若有多条线段符合条件,输出编号最小的线段的编号)

洛谷板子题-Segment[HEOI2013]-洛谷T4097

二、add操作

整个李超线段树的核心就是add操作

1.特判 l == r

已经到了一个点

如果该点之前没有维护线段,直接维护现在的线段

如果该点已经维护过,选择纵坐标靠上的直线(点),纵坐标相同,选择编号较小的

2.如果没有恰好放在区间里

如果不过mid,根据与mid关系左右查找

如果过mid,劈两半分别查找

3.如果找到了恰好的区间

如果该区间没有维护线段,维护该线段

如果有,

(1).如果中点处新的有,留下新的,把旧的中,稍大的一般留下(全劣则淘汰),下放到对应的子区间。

(2).如果中点处值相同。一般情况选择新的劈断的下放(省的建线段)。但是当新的编号较小,并且新的线段的右端点的纵坐标大于等于旧的,将旧的右半部分下放(使mid处一定取得的使新的线段,也就是编号较小的)

(3).如果中点处旧的优,同理...

//李超线段树
#include<cstdio>
#include<algorithm>
using namespace std;

inline int read()
{
    int sum = 0,p = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
            p = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (sum *= 10) += ch - '0';
        ch = getchar();
    }
    return sum * p;
}

#define mid ((l + r)>>1)
#define lson l,mid,o<<1
#define rson mid + 1,r,o<<1|1

const int mod1 = 39989,mod2 = 1e9,N = 50100;;
int n,ans,lastans,id;//ans实际答案,lastans上次查询的答案,id给函数编的号 
int  sx1[N << 2],sx2[N << 2],sy1[N << 2],sy2[N << 2],sum[N << 2];
bool vis[N << 2];
double tval;

//求节点储存的原函数的o点的值 
double G(int o,int x1,int y1,int x2,int y2)
{
    if(x1 == x2)
        return y2;
    else
        return 1.0 *(o - x2) *(y1 - y2)/(x1 - x2) +y2;
}

//当新加入的函数是一条垂直于x轴的直线时 的修改操作 
void change(int x,int v,int tot,int l,int r,int o)
{
    if(l == r)
    {
        if(!vis[o])
        {
            sx1[o] = sx2[o] = l;
            sy1[o] = sy2[o] = v;
            sum[o] = tot;
            vis[o] = true;
        }
        else
        {
            double cnt = G(x,sx1[o],sy1[o],sx2[o],sy2[o]);
            if(cnt > v || (cnt == v && tot < sum[o]))
            {
                sx1[o] = sx2[o] = l;
                sy1[o] = sy2[o] = v;
                sum[o] = tot;
            }
        }
        return;
    }
    if(mid >= x)
        change(x,v,tot,lson);
    else
        change(x,v,tot,rson);
}

//求两个函数的交点 
double Inter(double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)
{
    double a,b,c,d,g,h,f,t,s;
    a = x2 - x1;
    b = x3 - x4;
    c = y2 - y1;
    d = y3 - y4;
    g = x3 - x1;
    h = y3 - y1;
    f = a *d - b * c;
    t = (d * g - b * h)/f;
    return x1 +t * (x2 - x1);
}

void update(int ql,int qr,int x1,int y1,int x2,int y2,int tot,int l,int r,int o)
{
    if(ql <= l && r <= qr)
    {
        if(!vis[o])
        {
            sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
            sum[o] = tot;
            vis[o] = true;
        }
        else
        {
            double f1,f2,f3,f4;
            f1 = G(l,x1,y1,x2,y2);
            f2 = G(l,sx1[o],sy1[o],sx2[o],sy2[o]);
            f3 = G(r,x1,y1,x2,y2);
            f4 = G(r,sx1[o],sy1[o],sx2[o],sy2[o]);
            if(f1 <= f2 && f3 <= f4)
                return;
            else if(f1 >= f2 && f3 >= f4)
            {
                sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
                sum[o] = tot;
            }
            else
            {
                double spot = Inter(x1,y1,x2,y2,sx1[o],sy1[o],sx2[o],sy2[o]);
                if(f1 >= f2)
                {
                    if(spot <= mid)
                        update(ql,qr,x1,y1,x2,y2,tot,lson);
                    else
                    {
                        update(ql,qr,sx1[o],sy1[o],sx2[o],sy2[o],sum[o],rson);
                        sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
                        sum[o] = tot;
                    }
                }
                else
                {
                    if(spot > mid)
                        update(ql,qr,x1,y1,x2,y2,tot,rson);
                    else
                    {
                        update(ql,qr,sx1[o],sy1[o],sx2[o],sy2[o],sum[o],lson);
                        sx1[o] = x1,sy1[o] = y1,sx2[o] = x2,sy2[o] = y2;
                        sum[o] = tot;
                    }
                }
            }
        }
        return;
    }
    if(ql <= mid)
        update(ql,qr,x1,y1,x2,y2,tot,lson);
    if(qr > mid)
        update(ql,qr,x1,y1,x2,y2,tot,rson);
}

void query(int x,int l,int r,int o)
{
    if(vis[o])
    {
        double cnt = G(x,sx1[o],sy1[o],sx2[o],sy2[o]);
        if(cnt > tval || cnt == tval && sum[o] < ans)
        {
            tval = cnt;
            ans = sum[o];
        }
    }
    if(l == r)
        return;
    if(mid >= x)
        query(x,lson);
    else
        query(x,rson);
}

int main()
{
    n = read();
    while(n--)
    {
        int opt = read();
        if(!opt)
        {
            int x = read();
            x = (x + lastans - 1)%mod1 + 1;
            ans = 0;
            tval = 0;
            query(x,1,50000,1);
            printf("%d
",ans);
            lastans = ans;
        }
        else
        {
            int x1 = read(),y1 = read(),x2 = read(),y2 = read();
            x1 = (x1 + lastans - 1)%mod1 + 1;
            y1 = (y1 + lastans - 1)%mod2 + 1;
            x2 = (x2 + lastans - 1)%mod1 + 1;
            y2 = (y2 + lastans - 1)%mod2 + 1;
            if(x1 > x2)
            {
                swap(x1,x2);
                swap(y1,y2);
            }
            if(x1 == x2)
                change(x1,max(y1,y2),++id,1,50000,1);
            else
                update(x1,x2,x1,y1,x2,y2,++id,1,50000,1);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/darlingroot/p/11248951.html