蓝桥杯双向排序线段树(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
    评论
下面是一个简单的线段树Python 实现模板: ```python class SegmentTree: def __init__(self, arr): self.arr = arr self.tree = [0] * (4 * len(arr)) self.build(0, 0, len(arr) - 1) def build(self, node, start, end): if start == end: self.tree[node] = self.arr[start] else: mid = (start + end) // 2 left_child = 2 * node + 1 right_child = 2 * node + 2 self.build(left_child, start, mid) self.build(right_child, mid + 1, end) self.tree[node] = self.tree[left_child] + self.tree[right_child] def query(self, node, start, end, left, right): # 区间完全包含在查询区间内 if left <= start and right >= end: return self.tree[node] # 区间完全不在查询区间内 if end < left or start > right: return 0 mid = (start + end) // 2 left_child = 2 * node + 1 right_child = 2 * node + 2 return self.query(left_child, start, mid, left, right) + self.query(right_child, mid + 1, end, left, right) def update(self, node, start, end, index, value): if start == end: self.arr[index] = value self.tree[node] = value else: mid = (start + end) // 2 left_child = 2 * node + 1 right_child = 2 * node + 2 if start <= index and index <= mid: self.update(left_child, start, mid, index, value) else: self.update(right_child, mid + 1, end, index, value) self.tree[node] = self.tree[left_child] + self.tree[right_child] ``` 使用这个模板,可以通过以下步骤来构建和使用线段树: 1. 创建一个 SegmentTree 对象,并传入原始数组作为参数。 2. 可以使用 `query` 方法来查询某个区间的和,传入查询区间的左右边界。 3. 可以使用 `update` 方法来更新原始数组中的某个元素,传入元素的索引和新的值。 注意,这只是一个简单的线段树模板,可以根据具体问题的需求进行适当修改和扩展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值