李超线段树 [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\n",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);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用和提到,Linux下安装ffmpeg是非常方便的。下面给出在Linux上安装ffmpeg的步骤: 1. 首先,需要安装Cygwin。Cygwin是一个在Windows上运行类似于Linux的环境的工具。可以从官方网站上下载并安装。 2. 安装完Cygwin后,打开终端,输入以下命令下载x264源代码并进行编译: ``` wget http://mirror.yandex.ru/mirrors/ftp.videolan.org/x264/snapshots/last_x264.tar.bz2 bunzip2 last_x264.tar.bz2 tar -vxf last_x264.tar cd last_x264 ./configure --enable-static --enable-shared --disable-asm --disable-avs make && sudo make install ``` 3. 然后,从ffmpeg官网下载ffmpeg源代码,并进行编译。编译方法可以参考官方文档或者在终端中输入以下命令: ``` wget http://ffmpeg.org/releases/ffmpeg-[版本号].tar.gz tar -xzvf ffmpeg-[版本号].tar.gz cd ffmpeg-[版本号] ./configure --enable-shared make sudo make install ``` 其中,是你想要安装的ffmpeg的版本号。 4. 编译完成后,就可以使用ffmpeg了。可以通过在终端中输入`ffmpeg`命令来验证是否安装成功。 请注意,以上步骤仅适用于在Linux系统上安装ffmpeg。如果你是在其他操作系统上进行安装,请参考相关的文档或者教程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Windows下编译安装 FFmpeg](https://blog.csdn.net/heng615975867/article/details/119821945)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值