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.
  • 相关阅读:
    python模块之linecache
    如何在cmd命令下运行python脚本
    Git remote: ERROR: missing Change-Id in commit message
    Git命令git update-index --assume-unchanged,忽略不想提交的文件(忽略跟踪)
    Git命令cherry-pick,选择把一部分代码提交到另一个分支
    Redis可以用来做什么?(摘自http://www.lianpenglin.cc廉鹏林博客)
    Yii笔记:打印sql、Form表单、时间插件、Mysql的 FIND_IN_SET函数使用、是否是post/ajax请求
    Yii1使用Gii生成模块实现CURD
    通过经纬度获取所属城市信息-php
    树莓派进阶之路 (010)
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/7966221.html
Copyright © 2011-2022 走看看