蓝桥杯双向排序线段树(python)

试题 历届真题 双向排序【第十二届】【省赛】【B组】

资源限制

内存限制:256.0MB   C/C++时间限制:1.0s   Java时间限制:3.0s   Python时间限制:5.0s

分析:

        一看题,对区间修改查询,想到线段树,但是如何定义状态呢?一开始想到维护差分,但是模拟了几次,发现没规律,然后又对着原数组模拟,发现如下规律:

        1.数组就两个状态,前半段是降区间,后半段是升区间,考虑记录每个数是属于升区间还是降区间。用1 表示升区间,0表示降区间。

        2.对每个有意义的操作(没意义的操作就是,例如输入0 5,但是前5个甚至前10个数都是降的,这个就是没意义的),无论是改成升序列 还是降序列,都是尽可能的改变小的,靠近1的值。这个可以自行模拟试一试,提示到这里了,希望读者能画一画。

上代码:

n,m=map(int,input().split())
class node():
    def __init__(self,lazy=-1,sum=1):
        self.lazy=lazy
        self.sum=sum   #对于叶子节点 1表示这个点在升序列 0在降序列 对于其他节点 sum记录了这个#区间的属于升序列的数的个数
tree=[node() for i in range(100000*4+100)]
def pushup(x):
    tree[x].sum=tree[x<<1].sum+tree[(x<<1)+1].sum
def pushdown(x,l,r):
    if (tree[x].lazy!=(-1)):  

        mid=(l+r)>>1
        tree[x<<1].lazy=tree[x].lazy
        tree[(x<<1)+1].lazy=tree[x].lazy
        tree[x<<1].sum=tree[x].lazy*(mid-l+1)
        tree[1+(x << 1)].sum = tree[x].lazy * (r-mid)
        tree[x].lazy=-1

def build(x,l,r):
    if (l==r):
        return
    mid=(l+r)>>1
    build(2*x,l,mid)
    build(2*x+1,mid+1,r)
    pushup(x)
    tree[x].lazy=-1

def update0(x,l,r,num): #将a1 到 am 降序 优先操作左端
    if (num>=tree[x].sum):  #我要将升序改成降序,如果要改的数量比全部的升序还多,直接全清空就好
        tree[x].sum=0
        tree[x].lazy=0
        return

    pushdown(x, l, r)
    num_l1 = tree[x << 1].sum

    mid = (l +r) >> 1
    if num<=num_l1:
        update0(2*x,l,mid,num)
    else :
        update0(2*x,l,mid,num_l1)
        update0(2*x+1,mid+1,r,num-num_l1)
    pushup(x)

def update1(x,l,r,num): #这是把降序变成升序,还是对左端优先处理
    numx = (r - l + 1) - tree[x].sum
    if (num>=numx):
        tree[x].sum=r-l+1
        tree[x].lazy=1
        return

    pushdown(x,l,r)
    mid=(l+r)>>1
    numl=(mid-l+1)-tree[x<<1].sum
    if num<=numl:
        update1(x*2,l,mid,num)
    else:
        update1(x*2,l,mid,numl)
        update1(x*2+1,mid+1,r,num-numl)
    pushup(x)

def query(x,l,r,i):
    if (l==r):
        return tree[x].sum
    pushdown(x,l,r)
    mid=(l+r)>>1
    if (i<=mid):
        return query(x*2,l,mid,i)
    else:
        return query(x*2+1,mid+1,r,i)
pre_i=1  #数组中升序列和降序列的分界,是升序列的第一个数
build(1,1,n)
for i in range(m):
    p,q=map(int,input().split())

    if (p): #增
        if (pre_i<=q):

            continue
        update1(1,1,n,pre_i-q)
        pre_i=q
    else:
        if pre_i>q:continue
        update0(1,1,n,q-pre_i+1)
        pre_i=q+1

s=[]  #记录升序列
j=[]  #降序列
for i in range(1,n+1):
    if (query(1,1,n,i)):
        s.append(i)
    else:
        j.append(i)
i=len(j)
while(i!=0):
    print(j[i-1],end=" ")
    i-=1
if (len(s)):
    for i in range(len(s) - 1):
        print(s[i], end=" ")
    print(s[-1])





通过情况:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值