zoukankan      html  css  js  c++  java
  • [BZOJ3011][Usaco2012 Dec]Running Away From the Barn

    题意

    给出一棵以1为根节点树,求每个节点的子树中到该节点距离<=l的节点的个数

    题解

    方法1:倍增+差分数组

    首先可以很容易的转化问题,考虑每个节点对哪些节点有贡献

    即每次对于一个节点,找到其第l个父亲,这个操作可以用倍增在logn时间内完成

    找到后将x-y这一段区间都加1,很容易想到用差分数组维护

    方法2:主席树

    考虑节点x和节点x的子树中的一个节点y,记点x到根节点的距离为dis[x]

    若dis[y]-dis[x]<=l则满足条件

    将不等式变形可得dis[y]<=dis[x]+l

    即对每个点以dis[ ]为权值插入树中,查询时查找比dis[x]+l小的节点个数

    这时很容易想到主席树,第一维对dis[x](维护的前缀也就是查询的答案),第二维对节点编号

    又由于先决条件是节点y是在x的子树中的,所以我们应弄出一个dfs序

    对于每一个节点,其子树即num[x]-----子树中num[y]的最大值

    其次,插入时为避免对之后的节点造成影响,应将dis[]从小到大进行插入

    注意到dis数据范围较大考虑对其离散化

    还有就是,主席树的题目空间往往不能浪费太多

    方法3:左偏树

    可以考虑,对于节点x的子树中的一个节点

    若x与这个节点的距离>l,那么x的父亲与这个节点的距离也一定>l

    所以可以考虑用左偏树来维护

    对于每个节点x,枚举它的儿子y,维护一个大根堆

    另外,两个点之间的距离可以用dis[1,y]-dis[1,x]表示

    **没仔细看题数据是longlong啊。。

    代码

    方法1:倍增+差分数组

    方法2:主席树

    uses math;
    type re=record
      a,b,c,num:int64;
    end;
    type ree=record
      h,t,x:longint;
    end;
    var
      i,j:longint;
      now,m,n,c,d,k,l,o,ans,x,tmp:int64;
      a,dis:array[1..500000]of re;
      f:array[1..500000]of boolean;
      num,fa,head,q:array[0..500000]of int64;
      p:array[0..5000000]of ree;
    procedure arr(x,y,z:int64);
    begin
      inc(l);
      a[l].a:=head[x];
      a[l].b:=y;
      a[l].c:=z;
      head[x]:=l;
    end;
    function dfs(x,y:int64):int64;
    var u,v:longint;
    begin
      f[x]:=false; dis[x].a:=y; dis[x].b:=x;
      inc(now); dis[x].num:=now;
      u:=head[x]; dfs:=now;
      while u<>0 do
      begin
        v:=a[u].b;
        if f[v] then dfs:=max(dfs,dfs(v,y+a[u].c));
        u:=a[u].a;
      end;
      dis[x].c:=dfs;
    end;
    procedure swap(var x,y:re);
    var tmp:re;
    begin
      tmp:=x; x:=y; y:=tmp;
    end;
    procedure qsort(h,t:int64);
    var i,j,mid:int64;
    begin
      i:=h; j:=t; mid:=dis[(h+t) div 2].a;
      repeat
        while dis[i].a<mid do inc(i);
        while dis[j].a>mid do dec(j);
        if i<=j then
        begin
          swap(dis[i],dis[j]);
          inc(i); dec(j);
        end;
      until i>j;
      if i<t then qsort(i,t);
      if h<j then qsort(h,j);
    end;
    procedure build(x,h,t:int64);
    var mid:int64;
    begin
      p[x].h:=x*2; p[x].t:=x*2+1; now:=max(now,x*2+1);
      if h=t then exit;
      mid:=(h+t) div 2;
      build(x*2,h,mid); build(x*2+1,mid+1,t);
    end;
    function find(x:int64):int64;
    var h,t,mid:int64;
    begin
      h:=1; t:=n;
      while h<t do
      begin
        mid:=(h+t) div 2+1;
        if dis[mid].a<=x then h:=mid else t:=mid-1;
      end;
      exit(h);
    end;
    procedure insert(pre,x,h,t:int64);
    var tmp,mid:longint;
    begin
      inc(now); p[now]:=p[pre]; inc(p[now].x); tmp:=now;
      if h=t then exit;
      mid:=(h+t) div 2;
      if (x<=mid) then
      begin
        insert(p[now].h,x,h,mid);
        p[tmp].h:=tmp+1;
      end else
      begin
        insert(p[now].t,x,mid+1,t);
        p[tmp].t:=tmp+1;
      end;
    end;
    function query(x,h1,t1,h,t:int64):int64;
    var mid:int64;
    begin
      if (h>t1) or (t<h1) then exit(0);
      if (h<=h1) and (t1<=t) then exit(p[x].x);
      mid:=(h1+t1) div 2;
      exit(query(p[x].h,h1,mid,h,t)+query(p[x].t,mid+1,t1,h,t));
    end;
    begin
      readln(n,k);  fillchar(f,sizeof(f),true);
      for i:=1 to n-1 do
      begin
        read(c,d); arr(i+1,c,d); arr(c,i+1,d);
      end;
      dfs(1,0);
      qsort(1,n); o:=0;
      for i:=1 to n do
      begin
        if (i=1) or (dis[i].a<>dis[i-1].a) then
          inc(o);
        num[i]:=o;
      end;
      now:=0; build(1,1,n);
      fa[0]:=1;
      for i:=1 to n do
      begin
        if (i<>1) and (num[i]=num[i-1]) then
        begin
          tmp:=now;
          insert(fa[num[i]],dis[i].num,1,n);
          fa[num[i]]:=tmp+1;
        end
        else
        begin
          fa[num[i]]:=now+1;
          insert(fa[num[i]-1],dis[i].num,1,n);
        end;
      end;
      for i:=1 to n do
      begin
        x:=find(dis[i].a+k);
        ans:=query(fa[num[x]],1,n,dis[i].num,dis[i].c);
        q[dis[i].b]:=ans;
      end;
      for i:=1 to n do writeln(q[i]);
    end.

     方法3:左偏树

    type re=record
      a,b,c:int64;
    end;
    var
      i,j:longint;
      m,n,ans,l,c,d:int64;
      k:int64;
      f:array[1..1000000]of boolean;
      a:array[1..1000000]of re;
      dis,left1,right1,fa,cnt,ll,head,vv,num:array[0..1000000]of int64;
    procedure arr(x,y,z:int64);
    begin
      inc(l);
      a[l].a:=head[x];
      a[l].b:=y;
      a[l].c:=z;
      head[x]:=l;
    end;
    function getfa(x:int64):int64;
    begin
      while (fa[x]<>0) do x:=fa[x];
      exit(x);
    end;
    procedure swap(var x,y:int64);
    var tmp:int64;
    begin
      tmp:=x; x:=y; y:=tmp;
    end;
    function merge(x,y:int64):int64;
    var tmp:int64;
    begin
      if (x=0) or (y=0) then exit(x+y);
      if (dis[x]<dis[y]) then swap(x,y);
      right1[x]:=merge(right1[x],y);
      fa[right1[x]]:=x;
      if (ll[left1[x]]<ll[right1[x]]) then swap(left1[x],right1[x]);
      ll[x]:=ll[right1[x]]+1; cnt[x]:=cnt[left1[x]]+cnt[right1[x]]+1;
      exit(x);
    end;
    function delete(x:int64):int64;
    var tmp:int64;
    begin
      fa[left1[x]]:=0; fa[right1[x]]:=0;
      if left1[x]<>0 then tmp:=left1[x] else tmp:=right1[x];
      merge(left1[x],right1[x]);
      exit(getfa(tmp));
    end;
    procedure dfs(x,y:int64);
    var u,v,c,d,goal,ans,z:int64;
    begin
      ans:=0;  f[x]:=false; dis[x]:=y;
      u:=head[x];
      while u<>0 do
      begin
        v:=a[u].b;
        if f[v] then
            begin
              dfs(v,y+a[u].c);
              c:=getfa(v); goal:=y+k;
              while (c<>0)  and (dis[c]>goal) do
              begin
                c:=delete(c);
              end;
              if c<>0 then
              begin
                ans:=ans+cnt[c];
                z:=getfa(x);
                merge(z,c);
              end;
            end;
        u:=a[u].a;
      end;
      if k>=0 then vv[x]:=ans+1 else vv[x]:=ans;
    end;
    begin
      readln(n,k);
      if k<0 then writeln('111');
      for i:=1 to n-1 do
      begin
        read(c,d); arr(i+1,c,d); arr(c,i+1,d);
      end;
      for i:=1 to n do cnt[i]:=1;
      fillchar(f,sizeof(f),true);
      dfs(1,0);
      for i:=1 to n do writeln(vv[i]);
    end.
  • 相关阅读:
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    64位WIN7系统 下 搭建Android开发环境
    在eclipse里 新建android项目时 提示找不到proguard.cfg
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    This Android SDK requires Android Developer Toolkit version 20.0.0 or above
    Android requires compiler compliance level 5.0 or 6.0. Found '1.4' instead
    Windows XP下 Android开发环境 搭建
    Android程序的入口点
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/7966221.html
Copyright © 2011-2022 走看看