魔法使的烟花(NOIP模拟赛Round 7)

【问题描述】

魔法森林里有很多蘑菇,魔法使常常采摘它们来制作魔法药水。为了在6月的那个奇妙的晚上用魔法绽放出最绚丽的烟花,魔法使决定对魔法森林进行一番彻底的勘探。

魔法森林分为n个区域,由n-1条长度相等的道路将它们连接为了无向连通图。每个区域都有一个等级,这n个区域的等级满足如下性质:

①1号区域的等级为1;

②由一条道路连接的两个区域(即相邻两个区域)等级相差为1;

③设两个区域x,y被一条道路连接,若x到1号区域的最短距离小于y到1号区域的最短距离,则有x到1号区域的最短路径上的所有区域的等级必定小于y的等级。

由于魔法森林各个区域的气候、地形、水文的不同,每个区域都有一个精华值,其中第i号区域的精华值为wi。整片魔法森林还有一个共鸣度m。每个区域吸收的精华值为一个包含该区域连通子图的精华值之和,由于共鸣度限制,能被一个区域吸收精华值的所有区域的等级必须比该区域的等级高x,x为不超过m的自然数。举个例子:

 

魔法使希望得到每个区域所吸收的精华值,这将有助于她规划蘑菇的采摘,于是她把这个任务交给了你,因为她还要去住在这附近的另一位魔法使家中喝杯茶。

【数据范围】

对于20%的数据,n,m<=1000;

对于70%的数据,n,m<=10^5;

对于另外10%的数据,m=n;

对于100%的数据,0<=n,m<=10^6,0<wi<=1000。

————————————————我是分割线————————————————

我们理解完这道题目后,显然就可以明白一个点对于答案的贡献就是在从该点开始向上爬m步所经过的节点上加上该点的精华值

所以就是在一个区间上增加自己的精华值

当然就可以用树上差分啦!

思路清晰,没什么可说的

下面贴代码

#include<cstdio>
using namespace std;
int val[1000005];
int st[1000005];
int fa[1000005];
int num,n,m,tp;
int head[1000005];
struct edge{
    int to,next;
}g[2000005];
void ins(int u,int v){g[++num].next=head[u];head[u]=num;g[num].to=v;}
void insw(int u,int v){ins(u,v);ins(v,u);}
void dfs(int u,int fat)
{
    register int y=tp-m;
    if(y<0)y=0;
    fa[st[y]]-=val[u];fa[u]+=val[u];st[++tp]=u;
    for(int i=head[u];i;i=g[i].next)
    {
        if(g[i].to==fat)continue;
        dfs(g[i].to,u);
        fa[u]+=fa[g[i].to];
    }
    tp--;
}
int main(){
    freopen("mushroom.in","r",stdin);
    freopen("mushroom.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&val[i]);
    int x,y;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        insw(x,y);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++)printf("%d\n",fa[i]);
    fclose(stdin);
    fclose(stdout);
}

 

posted @ 2017-06-03 15:34  ghostfly233  阅读(196)  评论(0编辑  收藏  举报