花花的森林

11 篇文章 0 订阅
4 篇文章 0 订阅

题目描述 花花有一棵带n 个顶点的树T,每个节点有一个点权ai。 有一天,他认为拥有两棵树更好一些。所以,他从T 中删去了一条边。
第二天,他认为三棵树或许又更好一些。因此,他又从他拥有的某一棵树中去除了一条边。
如此往复。每一天,花花都会删去一条尚未被删去的边,直到他得到了一个包含了n 棵只有一个点的树的森林。
定义一条简单路径1的权值为路径上点权之和,一棵树的直径为树上权值最大的简单路径。
花花认为树最重要的特征就是它的直径。所以他想请你算出任一时刻他拥有的所有树的直径的乘积。因为这个数可能很大,他要求你输出乘积对10^9 +
7 取模之后的结果。 输入 输入的第一行包含一个整数n,表示树T 上顶点的数量。 下一行包含n 个空格分隔的整数ai,表示顶点的权值。
之后的n-1 行中,每一行包含两个用空格分隔的整数xi 和yi,表示节点xi 和yi 之间连有一条边,编号为i。 再之后n-1
行中,每一行包含一个整数kj,表示在第j 天里会被删除的边的编号 输出 输出n 行。 在第i 行,输出删除i-1
条边之后,所有树直径的乘积对10^9 + 7 取模的结果。
样例输入
3
1 2 3
1 2
1 3
2
1
样例输出
6
9
6

提示
初始,树的直径为6(由节点2、1 和3 构成的路径)。在第一天之后,得到了两棵直径都为3的树。第二天之后,得到了三棵直径分别为1,2,3 的树,乘积为6。 顶点不重复出现的路径
• 对于40% 的数据:N <= 100;
•另有20% 的数据:N <= 1000;
• 另有20% 的数据:N <= 10^4;
• 对于100% 的数据:N <= 10^5; ai<= 10^4。

倒着加边,并查集维护。有一个结论两颗子树合并,其直径端点一定在原直径端点上。由于原图是树,所以我们可以采用倍增LCA来求解两点间的距离。

const p=1000000007;
var
tot,i,n,m,x1,x2,y1,y2,x,y,d,root1,root2,max,z:longint;
ret,next,head,fa,deep,w,q,u,v:array[0..200022] of longint;
ans,l:array[0..200022] of int64;
f,dis,s:array[0..200000,0..20] of int64;
procedure ins(u,v:longint);
begin
  tot:=tot+1;
  ret[tot]:=v;
  next[tot]:=head[u];
  head[u]:=tot;
end;

function gpow(x,k:longint):int64;
var
t:int64;
begin
  if k=1 then exit(x);
  t:=gpow(x,k div 2);
  t:=t*t mod p;
  if k mod 2=1 then t:=t*x mod p;
  exit(t);
end;

function find(i:longint):longint;
begin
  if fa[i]<>i then fa[i]:=find(fa[i]);
  exit(fa[i]);
end;

procedure dfs(u,pre:longint);
var
i,v:longint;
begin
  i:=head[u];
  while i<>0 do
  begin
    v:=ret[i];
    if v<>pre then
    begin
      deep[v]:=deep[u]+1;
      f[v,0]:=u;
      dis[v,0]:=w[v]+w[u];
      dfs(v,u);
    end;
    i:=next[i];
  end;
end;

procedure init;
var
i,j:longint;
begin
  j:=1;
  while (1<<j)<=n do
  begin
    for i:=1 to n do
      if f[i,j-1]<>-1 then
      begin
        f[i,j]:=f[f[i,j-1],j-1];
        dis[i,j]:=dis[i,j-1]+dis[f[i,j-1],j-1]-w[f[i,j-1]];
      end;
    j:=j+1;
  end;
end;

function lca(a,b:longint):longint;
var
i,j,t:longint;
begin
  d:=w[a]+w[b];
  if deep[a]<deep[b] then begin t:=a;a:=b;b:=t; end;
  i:=0;
  while (1<<i)<=deep[a] do
    i:=i+1;
  i:=i-1;
  for j:=i downto 0 do
    if (deep[a]-1<<j)>=deep[b] then
    begin
      d:=d+dis[a,j]-w[a];
      a:=f[a,j];
    end;
  if a=b then begin d:=d-w[a]; exit(a); end;
  for j:=i downto 0 do
    if (f[a,j]<>-1)and(f[a,j]<>f[b,j]) then
    begin
      d:=d+dis[a,j]-w[a];
      d:=d+dis[b,j]-w[b];
      a:=f[a,j];
      b:=f[b,j];
    end;
  d:=d+w[f[a,0]];
  exit(f[a,0]);
end;

begin
  readln(n);
  ans[n]:=1;
  for i:=1 to n do
  begin
    read(w[i]);
    ans[n]:=ans[n]*w[i] mod p;
  end;
  readln;
  for i:=1 to n-1 do
  begin
    readln(u[i],v[i]);
    ins(u[i],v[i]);
    ins(v[i],u[i]);
  end;
  for i:=1 to n-1 do
    readln(q[i]);
  deep[1]:=1;
  dis[1,0]:=w[1];
  dfs(1,-1);
  f[1,0]:=-1;
  init;
  for i:=1 to n do
  begin
    fa[i]:=i;
    s[i,1]:=i;
    s[i,2]:=i;
    l[i]:=w[i];
  end;
  for i:=n-1 downto 1 do
  begin
    root1:=find(u[q[i]]);
    root2:=find(v[q[i]]);
    x1:=s[root1,1];
    x2:=s[root1,2];
    y1:=s[root2,1];
    y2:=s[root2,2];
    if l[root1]>l[root2] then
    begin
      max:=l[root1];
      x:=x1;
      y:=x2;
    end
    else
    begin
      max:=l[root2];
      x:=y1;
      y:=y2;
    end;
    z:=lca(x1,y1);
    if d>max then
    begin
      max:=d;
      x:=x1;
      y:=y1;
    end;
    z:=lca(x1,y2);
    if d>max then
    begin
      max:=d;
      x:=x1;
      y:=y2;
    end;
    z:=lca(x2,y1);
    if d>max then
    begin
      max:=d;
      x:=x2;
      y:=y1;
    end;
    z:=lca(x2,y2);
    if d>max then
    begin
      max:=d;
      x:=x2;
      y:=y2;
    end;
    ans[i]:=ans[i+1]*gpow(l[root1]*l[root2] mod p,p-2) mod p*max mod p;
    fa[root1]:=root2;
    l[root2]:=max;
    s[root2,1]:=x;
    s[root2,2]:=y;
  end;
  for i:=1 to n do
    writeln(ans[i]);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值