【BZOJ2733】永无乡(线段树,启发式合并)

题意:支持合并,求块内K小数

对于 100%的数据 n≤100000,m≤n,q≤300000 

思路:对于每一个块建立一棵动态开点的线段树,暴力(启发式?)合并后二分下就行了

merge用函数的方式写因为懒得讨论x,y其中一个为0的情况,反正是把节点y并到x上

为什么这么暴力都不T?大概是因为随机数据的块的大小太平均了吧

  1 var t:array[0..2100000,0..1]of longint;
  2     sum:array[0..2100000]of longint;
  3     fa,a,root:array[0..300000]of longint;
  4     n,m,x,y,k,i,j,s,cnt,p,q:longint;
  5     ch:string;
  6 
  7 function find(k:longint):longint;
  8 begin
  9  if fa[k]<>k then fa[k]:=find(fa[k]);
 10  exit(fa[k]);
 11 end;
 12 
 13 procedure pushup(x:longint);
 14 var l,r:longint;
 15 begin
 16  l:=t[x,0]; r:=t[x,1];
 17  sum[x]:=sum[l]+sum[r];
 18 end;
 19 
 20 procedure update(l,r,x:longint;var p:longint);
 21 var mid:longint;
 22 begin
 23  if p=0 then
 24  begin
 25   inc(cnt); p:=cnt;
 26  end;
 27  if l=r then
 28  begin
 29   inc(sum[p]); exit;
 30  end;
 31  mid:=(l+r)>>1;
 32  if x<=mid then update(l,mid,x,t[p,0])
 33   else update(mid+1,r,x,t[p,1]);
 34  pushup(p);
 35 end;
 36 
 37 function merge(x,y:longint):longint;
 38 var mid:longint;
 39 begin
 40  if (x=0)or(y=0) then exit(x+y);
 41  t[x,0]:=merge(t[x,0],t[y,0]);
 42  t[x,1]:=merge(t[x,1],t[y,1]);
 43  pushup(x);
 44  exit(x);
 45 end;
 46 
 47 
 48 function query(l,r,k,p:longint):longint;
 49 var mid,tmp:longint;
 50 begin
 51  if sum[p]<k then exit(-1);
 52  if l=r then exit(a[l]);
 53  tmp:= sum[t[p,0]];
 54  mid:=(l+r)>>1;
 55  if tmp>=k then exit(query(l,mid,k,t[p,0]))
 56   else exit(query(mid+1,r,k-tmp,t[p,1]));
 57 end;
 58 
 59 begin
 60  assign(input,'bzoj2733.in'); reset(input);
 61  assign(output,'bzoj2733.out'); rewrite(output);
 62  readln(n,m);
 63  for i:=1 to n do
 64  begin
 65   read(x); a[x]:=i;
 66   update(1,n,x,root[i]);
 67  end;
 68  for i:=1 to n do fa[i]:=i;
 69  for i:=1 to m do
 70  begin
 71   readln(x,y);
 72   p:=find(x); q:=find(y);
 73   if p<>q then
 74   begin
 75    fa[q]:=p;
 76    merge(root[p],root[q]);
 77   end;
 78  end;
 79  readln(m);
 80  for i:=1 to m do
 81  begin
 82   readln(ch);
 83   s:=0; x:=0; y:=0; k:=length(ch);
 84   for j:=2 to k do
 85   begin
 86    if ch[j]=' ' then begin inc(s); continue; end;
 87    if s=1 then x:=x*10+ord(ch[j])-ord('0');
 88    if s=2 then y:=y*10+ord(ch[j])-ord('0');
 89   end;
 90   case ch[1] of
 91    'Q':writeln(query(1,n,y,root[find(x)]));
 92    'B':
 93    begin
 94     p:=find(x); q:=find(y);
 95     if p<>q then
 96     begin
 97      fa[q]:=p; root[p]:=merge(root[p],root[q]);
 98     end;
 99    end;
100   end;
101  end;
102 
103 
104  close(input);
105  close(output);
106 end.

 

posted on 2017-02-25 11:49  myx12345  阅读(212)  评论(0编辑  收藏  举报

导航