zoukankan      html  css  js  c++  java
  • 【BZOJ3697】采药人的路径(点分治)

    题意:采药人的药田是一个树状结构,每条路径上都种植着同种药材。
    采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
    采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。

    n<=100000

    思路:RYZ作业

    From hzwer:

    来自出题人hta的题解。。

    本题可以考虑树的点分治。问题就变成求过根满足条件的路径数。

    路径上的休息站一定是在起点到根的路径上,或者根到终点的路径上。

    如何判断一条从根出发的路径是否包含休息站?只要在dfs中记录下这条路径的和x,同时用个标志数组判断这条路径是否存在前缀和为x的节点。

    这样我们枚举根节点的每个子树。用f[i][0…1],g[i][0…1]分别表示前面几个子树以及当前子树和为i的路径数目,0和1用于区分路径上是否存在前缀和为i的节点。那么当前子树的贡献就是f[0][0] * g[0][0] + Σf [i][0] * g [-i][1] + f[i][1] * g[-i][0] + f[i][1] * g[-i][1],其中i的范围[-d,d],d为当前子树的深度。

      1 var head,vet,next,len,d,dis,son,flag,dep:array[1..210000]of longint;
      2     c:array[0..110000]of longint;
      3     b:array[-100000..100000]of longint;
      4     f,g:array[-100000..100000,0..1]of int64;
      5     n,m,i,x,y,z,tot,sum,root,mxdep:longint;
      6     ans:int64;
      7 
      8 procedure add(a,b,c:longint);
      9 begin
     10  inc(tot);
     11  next[tot]:=head[a];
     12  vet[tot]:=b;
     13  len[tot]:=c;
     14  head[a]:=tot;
     15 end;
     16 
     17 function max(x,y:longint):longint;
     18 begin
     19  if x>y then exit(x);
     20  exit(y);
     21 end;
     22 
     23 procedure getroot(u,fa:longint);
     24 var e,v:longint;
     25 begin
     26  son[u]:=1; c[u]:=0;
     27  e:=head[u];
     28  while e<>0 do
     29  begin
     30   v:=vet[e];
     31   if (v<>fa)and(flag[v]=0) then
     32   begin
     33    getroot(v,u);
     34    son[u]:=son[u]+son[v];
     35    c[u]:=max(c[u],son[v]);
     36   end;
     37   e:=next[e];
     38  end;
     39  c[u]:=max(c[u],sum-c[u]);
     40  if c[u]<c[root] then root:=u;
     41 end;
     42 
     43 procedure dfs(u,fa:longint);
     44 var e,v:longint;
     45 begin
     46  mxdep:=max(mxdep,dep[u]);
     47  if b[dis[u]]>0 then inc(f[dis[u],1])
     48   else inc(f[dis[u],0]);
     49  inc(b[dis[u]]);
     50  e:=head[u];
     51  while e<>0 do
     52  begin
     53   v:=vet[e];
     54   if (v<>fa)and(flag[v]=0) then
     55   begin
     56    dep[v]:=dep[u]+1;
     57    dis[v]:=dis[u]+len[e];
     58    dfs(v,u);
     59   end;
     60   e:=next[e];
     61  end;
     62  dec(b[dis[u]]);
     63 end;
     64 
     65 procedure solve(u:longint);
     66 var e,v,i,mx:longint;
     67 begin
     68  mx:=0;
     69  flag[u]:=1; g[0,0]:=1;
     70  e:=head[u];
     71  while e<>0 do
     72  begin
     73   v:=vet[e];
     74   if flag[v]=0 then
     75   begin
     76    dis[v]:=len[e];
     77    dep[v]:=1; mxdep:=1;
     78    dfs(v,u);
     79    mx:=max(mx,mxdep);
     80    ans:=ans+(g[0,0]-1)*f[0,0];
     81    for i:=-mxdep to mxdep do
     82     ans:=ans+g[-i,1]*f[i,1]+g[-i,0]*f[i,1]+g[-i,1]*f[i,0];
     83    for i:=-mxdep to mxdep do
     84    begin
     85     g[i,0]:=g[i,0]+f[i,0];
     86     g[i,1]:=g[i,1]+f[i,1];
     87     f[i,0]:=0; f[i,1]:=0;
     88    end;
     89   end;
     90   e:=next[e];
     91  end;
     92  for i:=-mx to mx do
     93  begin
     94   g[i,0]:=0; g[i,1]:=0;
     95  end;
     96  e:=head[u];
     97  while e<>0 do
     98  begin
     99   v:=vet[e];
    100   if flag[v]=0 then
    101   begin
    102    sum:=son[v]; root:=0;
    103    getroot(v,0);
    104    solve(root);
    105   end;
    106   e:=next[e];
    107  end;
    108 end;
    109 
    110 begin
    111  assign(input,'bzoj3697.in'); reset(input);
    112  assign(output,'bzoj3697.out'); rewrite(output);
    113  readln(n);
    114  for i:=1 to n-1 do
    115  begin
    116   readln(x,y,z);
    117   if z=0 then z:=-1;
    118   add(x,y,z);
    119   add(y,x,z);
    120  end;
    121  root:=0; sum:=n; c[0]:=n;
    122  getroot(1,0);
    123  solve(root);
    124  writeln(ans);
    125  close(input);
    126  close(output);
    127 end.
  • 相关阅读:
    ZOJ 3018
    poj2464
    Gauss
    【C】关于内存地址
    【C】typedef与define的区别
    C位移操作
    操作系统使用批处理文件更改网络配置
    【Linux】查看某个进程的线程数量(转)
    数据结构快速排序
    C++Explanation of ++val++ and ++*p++ in C
  • 原文地址:https://www.cnblogs.com/myx12345/p/6526257.html
Copyright © 2011-2022 走看看