bzoj3165 [Heoi2013]Segment

Description
要求在平面直角坐标系下维护两个操作:
1.在平面上加入一条线段。记第i条被插入的线段的标号为i。
2.给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。

Input
第一行一个整数n,表示共n 个操作。
接下来n行,每行第一个数为0或1。
若该数为 0,则后面跟着一个正整数 k,表示询问与直线
x = ((k +lastans–1)%39989+1)相交的线段中交点(包括在端点相交的情形)最靠上的线段的编号,其中%表示取余。若某条线段为直线的一部分,则视作直线与线段交于该线段y坐标最大处。若有多条线段符合要求,输出编号最小的线段的编号。
若该数为 1,则后面跟着四个正整数 x0, y0, x 1, y 1,表示插入一条两个端点为
((x0+lastans-1)%39989+1,(y0+lastans-1)%10^9+1)和((x
1+lastans-1)%39989+1,(y1+lastans-1)%10^9+1) 的线段。
其中lastans为上一次询问的答案。初始时lastans=0。

Output
对于每个 0操作,输出一行,包含一个正整数,表示交点最靠上的线段的编号。若不存在与直线相交的线段,答案为0。

Sample Input
6
1 8 5 10 8
1 6 7 2 6
0 2
0 9
1 4 7 6 7
0 5

Sample Output
2
0 3

HINT
对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。

分析:
终于要学习新的数据结构了
灰常的兴奋啊~~
新知识的学习从抄板子开始
从零开始的数据结构学习。。。
丁队的板子。。。看不懂
只能上网找资源orz
李超线段树板子
这里写图片描述
这里写图片描述

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>

using namespace std;

const double eps=1e-10;
const int swt=1000000000;
const int N=100010;
const int mod=39989;
struct nd{
    int x,y,ff;
};
nd tree[N<<2];
struct node{
    int x,y;
    double k,b;
    double f(int x){
        return k*x+b;
    }
};
node li[N];  //线段 
int lastans,tot=0,ansi,wi[N];
double ansy,wy[N];  //ansy记录最大坐标,ansi记录线段编号 

int dcmp(double x)
{
    if (fabs(x)<eps) return 0;
    else if (x>0) return 1;
    else return -1;
}

int cross(int u,int w)  //交点 
{
    return floor((li[w].b-li[u].b)/(li[u].k-li[w].k));
}

node getline(int x,int y,int xx,int yy)
{
    node ans;
    ans.x=min(x,xx);  //定义域
    ans.y=max(x,xx);
    if (ans.x!=ans.y){
        ans.k=(double)(yy-y)/(double)(xx-x);
        ans.b=y-x*ans.k;  //kx+b=y
    } 
    else ans.k=0.0,ans.b=max(y,yy);  //一条竖线
    return ans; 
}

void update(int u,int x)  //x=u和线段的交点 
{
    double y=li[x].f(u);
    int p=dcmp(y-wy[u]);
    if (!wi[u]||(p>0||(p==0&&x<wi[u])))
    {
        wy[u]=y;   //维护端点值 
        wi[u]=x;
    }
}

void build(int bh,int l,int r)
{
    tree[bh].x=l;
    tree[bh].y=r;
    tree[bh].ff=0;
    if (l==r) return;
    int mid=(l+r)>>1;
    build(bh<<1,l,mid); build(bh<<1|1,mid+1,r);
}

void insert(int bh,int u)  //把每个线段分成logn个区间 
{
    if (li[u].x<=tree[bh].x&&li[u].y>=tree[bh].y)  //线段树节点完全包含线段 
    {
        if (!tree[bh].ff){
            tree[bh].ff=u;return;  ///没被覆盖过 
        }
        int mid=(tree[bh].x+tree[bh].y)>>1;
        int ll=dcmp(li[u].f(tree[bh].x)-li[tree[bh].ff].f(tree[bh].x));  
        int rr=dcmp(li[u].f(tree[bh].y)-li[tree[bh].ff].f(tree[bh].y));
        //通过f函数计算线段树节点的左右端点与两条线段的交点
        if (ll>0&&rr>0)  //完全覆盖
           tree[bh].ff=u;
        else if (ll>0||rr>0) //李超线段树的精髓啊 
        {
            int tt=cross(tree[bh].ff,u);
            if (tt<=mid&&ll>0) insert(bh<<1,u);
            if (tt<=mid&&rr>0) insert(bh<<1,u),tree[bh<<1|1].ff=u;  //
            if (tt>mid&&rr>0) insert(bh<<1|1,u);
            if (tt>mid&&ll>0) insert(bh<<1|1,u),tree[bh<<1].ff=u;  //
        } else update(tree[bh].x,u),update(tree[bh].y,u);
        return;
    }
    int mid=(tree[bh].x+tree[bh].y)>>1;
    if (li[u].x<=mid) insert(bh<<1,u);
    if (li[u].y>mid) insert(bh<<1|1,u); 
}

void ask(int bh,int u)
{
    if (tree[bh].ff)
    {
        double y=li[tree[bh].ff].f(u);
        int s=dcmp(y-ansy);
        if (s>0||(s==0&&ansi>tree[bh].ff))
            ansy=y,ansi=tree[bh].ff;
    }
    if (tree[bh].x==tree[bh].y) return;
    int mid=(tree[bh].x+tree[bh].y)>>1;
    if (u<=mid) ask(bh<<1,u);
    if (u>mid) ask(bh<<1|1,u);
}

int main()
{
    int T;
    scanf("%d",&T);
    build(1,1,mod);
    while (T--)
    {
        int opt,x,y,xx,yy;
        scanf("%d",&opt);
        if (opt==1)
        {
            scanf("%d%d%d%d",&x,&y,&xx,&yy);
            x=(x+lastans-1)%mod+1;y=(y+lastans-1)%swt+1;
            xx=(xx+lastans-1)%mod+1;yy=(yy+lastans-1)%swt+1;
            li[++tot]=getline(x,y,xx,yy);
            insert(1,tot);
        }
        else
        {
            scanf("%d",&x);
            x=(x+lastans-1)%mod+1;
            ansi=0;ansy=-1.0;
            ask(1,x);
            int s=dcmp(wy[x]-ansy);
            if (s>0||(s==0&&wi[x]<ansi)) ansi=wi[x];
            lastans=ansi;
            printf("%d
",lastans);
        }
    } 
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673411.html