题意:支持合并,求块内K小数
对于 100%的数据 n≤100000,m≤n,q≤300000
思路:对于每一个块建立一棵动态开点的线段树,暴力(启发式?)合并后二分下就行了
merge用函数的方式写因为懒得讨论x,y其中一个为0的情况,反正是把节点y并到x上
为什么这么暴力都不T?大概是因为随机数据的块的大小太平均了吧
var t:array[0..2100000,0..1]of longint; sum:array[0..2100000]of longint; fa,a,root:array[0..300000]of longint; n,m,x,y,k,i,j,s,cnt,p,q:longint; ch:string; function find(k:longint):longint; begin if fa[k]<>k then fa[k]:=find(fa[k]); exit(fa[k]); end; procedure pushup(x:longint); var l,r:longint; begin l:=t[x,0]; r:=t[x,1]; sum[x]:=sum[l]+sum[r]; end; procedure update(l,r,x:longint;var p:longint); var mid:longint; begin if p=0 then begin inc(cnt); p:=cnt; end; if l=r then begin inc(sum[p]); exit; end; mid:=(l+r)>>1; if x<=mid then update(l,mid,x,t[p,0]) else update(mid+1,r,x,t[p,1]); pushup(p); end; function merge(x,y:longint):longint; var mid:longint; begin if (x=0)or(y=0) then exit(x+y); t[x,0]:=merge(t[x,0],t[y,0]); t[x,1]:=merge(t[x,1],t[y,1]); pushup(x); exit(x); end; function query(l,r,k,p:longint):longint; var mid,tmp:longint; begin if sum[p]<k then exit(-1); if l=r then exit(a[l]); tmp:= sum[t[p,0]]; mid:=(l+r)>>1; if tmp>=k then exit(query(l,mid,k,t[p,0])) else exit(query(mid+1,r,k-tmp,t[p,1])); end; begin assign(input,‘bzoj2733.in‘); reset(input); assign(output,‘bzoj2733.out‘); rewrite(output); readln(n,m); for i:=1 to n do begin read(x); a[x]:=i; update(1,n,x,root[i]); end; for i:=1 to n do fa[i]:=i; for i:=1 to m do begin readln(x,y); p:=find(x); q:=find(y); if p<>q then begin fa[q]:=p; merge(root[p],root[q]); end; end; readln(m); for i:=1 to m do begin readln(ch); s:=0; x:=0; y:=0; k:=length(ch); for j:=2 to k do begin if ch[j]=‘ ‘ then begin inc(s); continue; end; if s=1 then x:=x*10+ord(ch[j])-ord(‘0‘); if s=2 then y:=y*10+ord(ch[j])-ord(‘0‘); end; case ch[1] of ‘Q‘:writeln(query(1,n,y,root[find(x)])); ‘B‘: begin p:=find(x); q:=find(y); if p<>q then begin fa[q]:=p; root[p]:=merge(root[p],root[q]); end; end; end; end; close(input); close(output); end.
时间: 2024-10-25 18:21:53