【loli的胡策】测试4.20(主席树+凸包)

T1:

n个数,m个询问,强制在线,每次给出l,r,求区间mex值
a[i]<=1e9,n,m<=200000

题解:

我为什么这么ZZ
这样的思路以前应该见过啊。
离线的做法?
首先处理出1~i的mex值用线段树维护,同时处理出nxt[i]表示这个数字的下一个位置
当我们把左节点右移的时候,会对i~nxt[i]这个区间造成的影响是:mex比这个数字大的全都要变成这个数字,也就是区间取min值

强制在线的做法?
我们换个思路,建立一棵主席树,每一棵线段树的节点i表示数字i出现的最右端
那么我们对于一个询问l,r,1~r区间内如果有一个前缀,他们所有的节点维护的最右端都>=l,那么说明他们都出现过了,这样的话,如果左区间有一个 < l的位置,那么答案肯定在左区间
这样我们对于这棵主席树维护一个min值,如果min < l说明答案在左边了
还有一个问题就是可以发现只有n个数字,那么mex肯定是0~n之间的一个数字
复杂度 O(nlogn) O ( n l o g n )

代码:

#include <cstdio>
#include <iostream>
using namespace std;
const int N=200005;
struct hh{int l,r,minn;}t[N*20];
int sz,root[N];
void insert(int &now,int l,int r,int v,int wz)
{
    t[++sz]=t[now]; now=sz;
    if (l==r)
    {
        t[now].minn=wz;
        return;
    }
    int mid=(l+r)>>1;
    if (v<=mid) insert(t[now].l,l,mid,v,wz);
    else insert(t[now].r,mid+1,r,v,wz);
    t[now].minn=min(t[t[now].l].minn,t[t[now].r].minn);
}
int qurry(int now,int l,int r,int a)
{
    if (l==r) return l;
    int mid=(l+r)>>1;
    if (t[t[now].l].minn<a) return qurry(t[now].l,l,mid,a);
    else return qurry(t[now].r,mid+1,r,a);
}
int main()
{
    freopen("mex.in","r",stdin);
    freopen("mex.out","w",stdout);
    int n,m,t,x;scanf("%d%d%d",&n,&m,&t);
    for (int i=1;i<=n;i++) 
    {
        scanf("%d",&x);
        root[i]=root[i-1];
        if (x<n) insert(root[i],0,n,x,i);
    }
    int ans=0;
    for (int i=1;i<=m;i++)
    {
        int l,r;scanf("%d%d",&l,&r);
        if (t==1) l^=ans,r^=ans;
        ans=qurry(root[r],0,n,l);
        printf("%d\n",ans);
    }
}

T2

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

题解:

首先我们考虑从一个点左右看过去能看到最高的顶点分别是哪个
我们单独考虑左侧,右侧同理,考虑前n个点的上凸壳。第n个点往左看去的最高点实际上就是在上凸壳上的某一个点
这里写图片描述
所以我们左右分别求一次上凸壳O(n),注意这个点本身就比左边高的情况

然后我们怎么求从每一个点出发需要经过的段数
假设从A号点出发,走到B点时,看到了比A更高的顶点,此时相当于从B重新出发
那么我们让A->B,可以发现这东西是一棵树,这样遍历可以得到答案

现在的问题是对于每一个A,如何快速找到B
定义F[A]表示A点能看到最高的高度,如果A往左走,我们要找到A左侧第一个B满足F[B]>=F[A],右边一样
那么我们按照每个点的F[A]从小到大排序,在原来点的顺序下构建双向链表,每次以F[A]的顺序访问一个点,此时双向链表中的元素的F值均>=F[A],所以我们只需要查询他的左侧点/右侧点就ok,然后删除他
复杂度 O(nlogn) O ( n l o g n )
记得叉积要开longlong啊

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int N=1000005;
struct po
{
    int x,y;
    po(int X=0,int Y=0){x=X,y=Y;}
}a[N];
struct hh{int v,t;}p[N];
int stack[N],top,fa[N],f[N],l[N],r[N];
po operator -(po a,po b){return po(a.x-b.x,a.y-b.y);}
bool operator <(hh a,hh b){return a.v<b.v||(a.v==b.v&&(a.t&1)<(b.t&1))||(a.v==b.v&&(a.t&1)==(b.t&1)&&a.t<b.t);}
LL cj(po a,po b){return (LL)a.x*b.y-(LL)b.x*a.y;}
int find(int x)
{
    top=0;
    while (x) stack[++top]=x,x=fa[x];
    for (int i=top-1;i;i--)
    {
        int now=stack[i];
        f[now]=f[fa[now]]+abs(fa[now]-now);
        fa[now]=0;
    }
}
int main()
{
    int n;scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
    top=0;
    for (int i=1;i<=n;i++)
    {
        while (top>1 && cj(a[i]-a[stack[top-1]],a[stack[top]]-a[stack[top-1]])<=0) top--;
        if (i==1 || a[i].y>=a[stack[top]].y) l[i]=i;else l[i]=stack[top];
        stack[++top]=i;
    }
    top=0;
    for (int i=n;i>=1;i--)
    {
        while (top>1 && cj(a[i]-a[stack[top-1]],a[stack[top]]-a[stack[top-1]])>=0) top--;
        if (i==n || a[i].y>a[stack[top]].y) r[i]=i;else r[i]=stack[top];
        stack[++top]=i;
    }
    for (int i=1;i<=n;i++)
      if (a[r[i]].y<a[l[i]].y)
      {
        p[i].v=a[l[i]].y;
        p[i].t=i<<1;
      }
      else
      {
        p[i].v=a[r[i]].y;
        p[i].t=i<<1|1;
      } 
    sort(p+1,p+n+1);
    for (int i=1;i<=n;i++)
      l[i]=i-1,r[i]=i+1;
    for (int i=1;i<=n;i++)
    {
        int now=p[i].t>>1;
        if (p[i].t&1)//往右走 
          fa[now]=r[now];
        else fa[now]=l[now];
        l[r[now]]=l[now];
        r[l[now]]=r[now];
    }
    fa[p[n].t>>1]=0;
    for (int i=1;i<=n;i++)
      if (fa[i]) find(i);
    for (int i=1;i<=n;i++) printf("%d\n",f[i]);
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值