zoukankan      html  css  js  c++  java
  • 李超线段树 [Heoi2013]Segment

    问题 D: [Heoi2013]Segment
    时间限制: 4 Sec 内存限制: 256 MB
    题目描述
    要求在平面直角坐标系下维护两个操作:
    1.在平面上加入一条线段。记第i条被插入的线段的标号为i。
    2.给定一个数k,询问与直线 x = k相交的线段中,交点最靠上的线段的编号。

    输入

    第一行一个整数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。

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

    样例输入
    6
    1 8 5 10 8
    1 6 7 2 6
    0 2
    0 9
    1 4 7 6 7
    0 5
    样例输出
    2
    0 3
    提示
    对于100%的数据,1 ≤ n ≤ 10^5 , 1 ≤ k, x0, x1 ≤ 39989, 1 ≤ y0 ≤ y1 ≤ 10^9。

    其实这道题就是个板子,李超线段树。(这个板子就是为了解决这个问题,只不过板子太难了而已,汗颜)

    就题论算法把,李超线段树用来处理向一个区间加有斜率的线段,之后判断某位置权值最大的线段是哪条之类的问题。而最重要的是多了的insert函数。当分到的区间已属于这条线段覆盖的区间是,就要进行更神奇的操作了,去比较当前节点所存的最优线段。先附上代码。

    void insert(int l,int r,int x,int k)
    {
        if(!t[x].h)t[x].h=k;
        if(cmp(t[x].h,k,l))swap(t[x].h,k);
        if(l==r||a[t[x].h].k==a[k].k)return;
        int mid=(l+r)/2;double g=(double)(a[t[x].h].b-a[k].b)/(a[k].k-a[t[x].h].k);
        if(g<l||g>r)return;
        if(g<=mid)insert(l,mid,x*2,t[x].h),t[x].h=k;
        else insert(mid+1,r,x*2+1,k);
    }

    因为比较分为两种情况,完全压制和在区间内有交点。完全压制不动或直接修改后返回就好了。而对于相交的就必须求出交点,根据交点的位置(其实也就是判断那条线段在交点那一边处于优势)去修改子区间。
    对于这段代码理解还是有点困难(本蒟蒻太水,自己口胡。。)要把本区间右侧较大的线段置成本区间最优(我也不是太懂为什么。。望神犇来解释),若不懂,手动模拟一下过程即可。
    还要注意一些细节:直线斜率是否存在,以及两条线是否平行。。(RE到死)

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 101000
    #define ll long long
    using namespace std;
    struct node
    {
        int l,r,id;double k,b;
    }a[N];
    struct tree{int l,r,h;}t[50000*4];
    int n,m;
    void build(int l,int r,int x)
    {
        t[x].l=l;t[x].r=r;
        if(l==r){t[x].h=0;return;}
        int mid=(l+r)/2;
        build(l,mid,x*2);
        build(mid+1,r,x*2+1);
    }
    bool cmp(int x,int y,double l)
    {
        if(!x)return 1;
        double l1=a[x].k*l+a[x].b,l2=a[y].k*l+a[y].b;
        return l1!=l2?l1<l2:x<y;
    }
    int q(int k,int x)
    {
        if(t[x].l==t[x].r)return t[x].h;
        int mid=(t[x].l+t[x].r)/2,tmp;
        if(k<=mid)tmp=q(k,x*2);
        else tmp=q(k,x*2+1);
        return cmp(t[x].h,tmp,k)?tmp:t[x].h;
    }
    void insert(int l,int r,int x,int k)
    {
        if(!t[x].h)t[x].h=k;
        if(cmp(t[x].h,k,l))swap(t[x].h,k);
        if(l==r||a[t[x].h].k==a[k].k)return;
        int mid=(l+r)/2;double g=(double)(a[t[x].h].b-a[k].b)/(a[k].k-a[t[x].h].k);
        if(g<l||g>r)return;
        if(g<=mid)insert(l,mid,x*2,t[x].h),t[x].h=k;
        else insert(mid+1,r,x*2+1,k);
    }
    void c(int k,int x)
    {
        if(t[x].l>=a[k].l&&t[x].r<=a[k].r)
            {insert(t[x].l,t[x].r,x,k);return;}
        int mid=(t[x].l+t[x].r)/2;
        if(a[k].l<=mid)c(k,x*2);
        if(a[k].r>mid)c(k,x*2+1);
    }
    int main()
    {
        scanf("%d",&n);int x1,x2,y1,y2,z,ans=0;
        build(1,50000,1);
        while(n--)
        {
            scanf("%d",&z);
            if(z==0)
            {
                scanf("%d",&x1);x1=(x1+ans-1)%39989+1;//out<<x1<<endl;
                ans=q(x1,1);
                printf("%d
    ",ans);
            }
            else
            {
                m++;
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                x1=(x1+ans-1)%39989+1;
                x2=(x2+ans-1)%39989+1;
                y1=(y1+ans-1)%1000000000+1;
                y2=(y2+ans-1)%1000000000+1;
                //cout<<x1<<" "<<x2<<" "<<y1<<" "<<y2<<endl;
                if(x1>x2)swap(x1,x2),swap(y1,y2);
                if(x1==x2)a[m].k=0,a[m].b=max(y1,y2);
                else
                {
                    a[m].k=(double)(y1-y2)/(x1-x2);
                    a[m].b=(double)y1-a[m].k*x1;
                }
                a[m].l=x1;a[m].r=x2;a[m].id=m;
                c(m,1);
            }
        }
    }
  • 相关阅读:
    hdu2191(多重背包)
    hdu3664(递推dp)
    hdu2955(变形01背包)
    hdu1712(分组背包)
    hdu1114(完全背包)
    hdu4004(二分)
    hdu2870(dp求最大子矩阵)
    POJ 1979 Red and Black(水题,递归)
    POJ 1922 Ride to School(贪心+模拟)
    POJ 1182 食物链(种类并查集)
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7632656.html
Copyright © 2011-2022 走看看