思路:本质上是动态区间求第k大问题,由于k被固定且很小,所以最朴素的算法是线段树维护区间前八大的值。
提示:蓝桥云课上这道题所有语言限制为1s,py肯定跑不过,去练习系统交。
code:
l,n=map(int,input().split())
c="C"
q="Q"
num=[0 for i in range(l+1)]
tree=[[] for i in range((n<<2)+100)]
def paixu(mid1,mid2):
l1=len(mid1)
l2=len(mid2)
if (l1+l2<8):
mid=mid1+mid2
mid.sort()
return mid[::-1]
else:
mid=[]
i,j,k=0,0,0
while (i<8 and j<l1 and k<l2):
if (mid1[j]>mid2[k]):
mid.append(mid1[j])
j+=1
i+=1
else:
mid.append(mid2[k])
k+=1
i+=1
while (i<8 and j<l1):
mid.append(mid1[j])
i+=1
j+=1
while (i<8 and k<l2):
mid.append(mid2[k])
k+=1
i+=1
return mid
def pushup(x):
mid1=tree[x<<1]
mid2=tree[x<<1|1]
tree[x]=paixu(mid1,mid2)
def query(x,l,r,a,b):
if (a<=l and r<=b ):
return tree[x]
mid=(l+r)>>1
mid1=[]
mid2=[]
if (a<=mid):
mid1=query(x<<1,l,mid,a,b)
if (b>mid):
mid2=query(x<<1|1,mid+1,r,a,b)
return paixu(mid1,mid2)
def update(x,l,r,ind,s):
if (l==r and l==ind):
tree[x]=[s]
return
mid=(l+r)>>1
if (ind<=mid):
update(x<<1,l,mid,ind,s)
if (ind>mid):
update(x<<1|1,mid+1,r,ind,s)
pushup(x)
for i in range(n):
a,b,d=map(str,input().split())
b=int(b)
d=int(d)
if (a==c):
update(1,1,l,b,d)
if (a==q):
mid=query(1,1,l,b,d)
if (len(mid)==8):
print(mid[7])
else:print(0)
通过情况:
但是这种方法毕竟不普适,比方说下次让你处理第16大呢?或者第k大呢,k是变的,这样就只能用树状数组套线段树了,但是python这个语言效率和空间的使用实在是,难崩。
先贴代码:
import bisect
class node1(): #存储询问
def __init__(self,opt,a,b):
self.opt=opt
self.a=a
self.b=b
"""class node(): #存储节点
def __init__(self):
#print(1)
self.son=[0,0]
self.v=0
"""
l1,n=map(int,input().split())
ls=[0 for i in range(100000*40)]
rs=[0 for i in range(100000*40)]
v=[0 for i in range(100000*40)]
root=[0 for i in range(105000)]
q=[]
C="C"
Q="Q"
num=[]
for i in range(n):
a,b,c=map(str,input().split())
b=int(b)
c=int(c)
q.append(node1(a,b,c))
if (a==C):
num.append(c)
num=list(set(num))
num.sort()
num=[0]+num
l2=len(num)-1
"""print(l2)"""
cnt=0
def tr_update(x,l,r,ind,t):
global cnt
if (x==0):
cnt+=1
x=cnt
if (l==r):
v[x]+=t
"""print(tree[x].v,x)"""
return x
mid=(r+l)>>1
if (ind<=mid):
x1=tr_update(ls[x],l,mid,ind,t)
ls[x]=x1
if (ind>mid):
x2=tr_update(rs[x],mid+1,r,ind,t)
rs[x]=x2
v[x]=v[ls[x]] +v[rs[x]]
"""print(v[x],v[rs[x]],v[ls[x]],x)"""
return x
def update(pos,ind,t):
i=pos
while (i<=l1):
root[i]=tr_update(root[i],1,l2,ind,t)
"""print(root[i])"""
i+=i&(-i)
def tr_query(l,r,k):
global lx, ly
sm=0
if (l==r):
for i in ly:
sm+=v[i]
for i in lx:
sm-=v[i]
if (k<=sm):
return l
return 0
mid=(l+r)>>1
for i in ly:
sm+=v[rs[i]]
for i in lx:
sm-=v[rs[i]]
if (sm>=k):
for i in range(len(ly)):
ly[i]=rs[ly[i]]
for i in range(len(lx)):
lx[i]=rs[lx[i]]
return tr_query(mid+1,r,k)
else:
for i in range(len(ly)):
ly[i] = ls[ly[i]]
for i in range(len(lx)):
lx[i] = ls[lx[i]]
return tr_query(l, mid, k-sm)
def query(a,b,k):
global lx,ly
i=a-1
while (i>0):
lx.append(root[i])
i-=i&(-i)
i=b
while (i>0):
ly.append(root[i])
i-=i&(-i)
return tr_query(1,l2,k)
s=[-1 for i in range(l1+10)]
def find(x):
return bisect.bisect(num,x)-1
for i in q:
if (i.opt==C):
if (s[i.a]==-1):
update(i.a,find(i.b),1)
s[i.a]=i.b
else:
update(i.a,find(s[i.a]),-1)
update(i.a, find(i.b), 1)
s[i.a] = i.b
else:
lx=[]
ly=[]
#print(i.a, i.b)
mo=query(i.a,i.b,8)
if (mo!=0):
print(num[mo])
else:
print(0)
我把node类删了,换成了数组,不然光初始化10e5*40的tree数组就得2s,就是这样还是只能过50%。
通过情况:
一言难尽,树状数组套线段树多么精美的算法到python这成了fv,还不如维护一个朴素的线段树好用。
不过再精妙的算法也都是用空间去换时间,用空间和时间去换功能,图1是我用cpp写的朴素线段树,图2是树套树,大家可以看下复杂度,和python对比一下哈哈哈。
就到这里吧,累了,弄这个弄了一天。