Bug2

来源:互联网 发布:控制网络流量软件 编辑:程序博客网 时间:2024/06/01 15:42

Bug2

题目描述

Bug2

之前的战斗使虫族的建筑遭到破坏,Bug需要组织大家一起重建被破坏的建筑。不过,为了合理分配任务,他需要仔细地考虑虫族的关系网络。

虫族的基地组织是一棵有根树,基地可看作是树的节点。每个基地i都有自身的影响力ai。树的边有一定的长度,记dis(u,v)表示基地u和基地v的距离。

关系网络的复杂性体现在两个基地可能会有控制的关系,我们说基地u控制基地v当且仅当:

  • u是v的祖先;
  • 且dis(u,v)≤av

Bug为了合理分配每个基地的任务,需要了解每个基地控制多少个基地。作为虫族总参谋,你能帮帮他吗?

输入格式

第一行一个正整数N,表示基地的个数。

第二行N个整数,第i个表示ai。1 ≤ ai ≤ 109

接下来N-1行,每行两个整数a,b。输入的第2+i行,表示基地i+1和基地a之间有一条边,且边的长度为b。1 ≤ a ≤ i;1 ≤ b ≤ 109

输出格式

一行,N个整数,第i个表示基地i控制多少个基地。

输入样例1

52 5 1 4 61 71 13 53 6

输出样例1

1 0 1 0 0

    这题的暴力,其实并不难想。在考试时,就想到了。但是,当时心烦意乱,想得不太清楚,又调了很久,仍然完美爆零。下次,暴力也一定要想清楚再写……

    暴力方法:对原图进行DFS。在DFS时,将当前点的所有祖先存入一个栈当中。从后面的祖先往前扫,如果dis(u,v)≤av,则祖先的控制力++。最后即可得出正确答案。

    dis(u,v)怎么求?不要笨笨地DFS,稍微转化一下,即可知道dis(u,v)=d[v]-d[u];(u,v与祖先的距离差值)。

  (PS:转化思想一定要时时挂在心头)

    正解,其实就是对暴力的小小优化。通过分析可以发现,如果u不能控制v,则u上方的其它v的祖先也一定不能控制v;如果u能控制v,则u下方的其它v的祖先也一定能控制v。这其中就有单调性。

    因此,可以用二分查找找出最上方的能够控制v的祖先up,将up及其以下的其它v的祖先的控制力都加1。但是显然,for循环累加会造成超时。怎么办呢?

    我们需要修改的元素,在栈中是连续的。修改区间值,可以用到线段树。不过较为复杂,这里不写。

    另一种方法,是在树上做差分。

    差分是什么?就是之前曾经接触过的某个DP模型。假设有n个值,每次将第s个到第t个都加上某个数y, 最后需要回答每个值的最终值。数据量大的情况下,直接for循环累加,会超时。解决方法是:f[s]+=y;f[t+1]-=y。第i个值的变化值即为f[1]+f[2]+……+f[i]的和。具体说明详见差分的题解(洛谷 语文成绩)。

    类似的,此处我们同样可以用差分。分析得知,从栈顶元素到up的控制力都要加1。可以这样操作:f[st[top]]++;F[st[up-1]]--。最后每个结点的控制力即为它及其子孙的f值之和。原理不难理解,可自行脑补。

    时间复杂度:O(NlogN)

    代码如下:

#include//printf#include#includeusing namespace std;const int MAXN=1e5+5;struct poi{int to;long long len;};vectoredge[MAXN];int n,end,an[MAXN],from,len,st[MAXN],z,f[MAXN];long long dis[MAXN],c[MAXN],a[MAXN];void dfs(int now){int lo=0,hi=z+1;//(lo,hi]while(lo+1=dis[now]-a[now])hi=mid;elselo=mid;}if(hi<=z){f[st[z]]++;f[st[lo]]--;}st[++z]=now;int size=edge[now].size();for(int i=0;i>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=2;i<=n;i++){cin>>from>>len;edge[from].push_back((poi){i,len});}dfs(1);run(1);for(int i=1;i<=n;i++)printf("%d ",an[i]);return 0;}