2018SD省队集训R1 D7

20 篇文章 0 订阅
16 篇文章 0 订阅

T1

题解:

代码:

T2

这里写图片描述

题解:

很明显我们可以转化一下看看,贪心的从最小的开始选择,每一个数字可以连向左边还没被扩进去的最大值,右边的第一个,或者是自己,维护区间最大值可以用线段树,维护哪些区间被用过可以用set。

这里写图片描述
则234被扎死口,234的值都是0;56未被扎死口,6的值是0。可以发现,被扎死口的元素值为0,值为0的元素不一定被扎死口,因为还可以向左连5,这里扎死口的概念就是能否越过这个点向左找值的意思

代码:

#include <set>
#include <cstdio>
#include <iostream>
#define INF 1e9
using namespace std;
const int N=100005;
set<int>s;int maxx[N*4],a[N],pos[N],n,ans[N];
void updata(int now){maxx[now]=max(maxx[now<<1],maxx[now<<1|1]);}
void change(int now,int l,int r,int x,int v)
{
    if (l==r){maxx[now]=v;return;}
    int mid=(l+r)>>1;
    if (x<=mid) change(now<<1,l,mid,x,v);
    else change(now<<1|1,mid+1,r,x,v);
    updata(now); 
}
int qurry(int now,int l,int r,int lrange,int rrange)
{
    if (lrange>rrange) return 0;
    if (lrange<=l && rrange>=r) return maxx[now];
    int mid=(l+r)>>1,ans=0;
    if (lrange<=mid) ans=qurry(now<<1,l,mid,lrange,rrange);
    if (rrange>mid) ans=max(ans,qurry(now<<1|1,mid+1,r,lrange,rrange));
    return ans;
}
void bl(int l,int r)
{
    for (int i=l;i<=r;i++) 
      change(1,1,n,i,0),s.insert(i);
    int z=r-l+1;
    for (int i=0;i<=r-l;i++) ans[a[l+(i-1+z)%z]]=a[l+i];
}
int main()
{
    freopen("perm.in","r",stdin);
    freopen("perm.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++) pos[a[i]]=i;
    for (int i=1;i<=n;i++) change(1,1,n,pos[i],i);
    s.insert(0);
    for (int i=1;i<=n;i++)
      if (!ans[i])
      {
        int wz=0,now=pos[i],maxx=0,zuo;
        wz=*--s.lower_bound(now);
        if (qurry(1,1,n,now,now)!=0) maxx=i,zuo=now;
        //可能已经被选了(被向右扩的结果 ,不能用s.count的原因是这个点不一定被扎死口,可能后边的还向前连 
        //被扎死口的一定是0,0的不一定被扎死口 
        if (!s.count(now+1)) //右边的已经被选过了
        {
            if (maxx<a[now+1]) maxx=a[now+1],zuo=now+1;
        } 
        if (wz+1<=now-1)
        {
            int z=qurry(1,1,n,wz+1,now-1);
            if (maxx<z) maxx=z,zuo=pos[z];
        }
        if (zuo==now)
        {
            s.insert(now);change(1,1,n,now,0);
            ans[i]=i;
            continue;
        }
        if (zuo==now+1)
        {
            change(1,1,n,now+1,0);
            continue;
        }
        bl(zuo,now);
      }
    for (int i=1;i<=n;i++) printf("%d ",ans[i]);
}

T3

题解:

代码:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值