首页 > 代码库 > 【BZOJ2733】永无乡(线段树合并)

【BZOJ2733】永无乡(线段树合并)

题意:支持合并,求块内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.

 

【BZOJ2733】永无乡(线段树合并)