Codeforces contest 1059 problem E——dfs+倍增+类似树链剖分

You are given a rooted tree on n vertices, its root is the vertex number 1. The i-th vertex contains a number wi. Split it into the minimum possible number of vertical paths in such a way that each path contains no more than L vertices and the sum of integers wi on each path does not exceed S. Each vertex should belong to exactly one path.

A vertical path is a sequence of vertices v1,v2,…,vk where vi (i≥2) is the parent of vi−1.

Input
The first line contains three integers n, L, S (1≤n≤105, 1≤L≤105, 1≤S≤1018) — the number of vertices, the maximum number of vertices in one path and the maximum sum in one path.

The second line contains n integers w1,w2,…,wn (1≤wi≤109) — the numbers in the vertices of the tree.

The third line contains n−1 integers p2,…,pn (1≤pi<i), where pi is the parent of the i-th vertex in the tree.

Output
Output one number — the minimum number of vertical paths. If it is impossible to split the tree, output −1.

Examples
inputCopy
3 1 3
1 2 3
1 1
outputCopy
3
inputCopy
3 3 6
1 2 3
1 1
outputCopy
2
inputCopy
1 1 10000
10001
outputCopy
-1
Note
In the first sample the tree is split into {1}, {2}, {3}.

In the second sample the tree is split into {1, 2}, {3} or {1, 3}, {2}.

In the third sample it is impossible to split the tree.

题意:

给你n,L,S表示n个点,每个点有一个权值,让你分成最少的链,并且这个链上每个点都是祖先关系,每条链最长是L,链上点的权值之和不超过S。最后给你从2开始的所有点的父亲,1是根。

题解:

首先我们可以肯定的是对于每一个点都是从叶子找上去的,否则会很难找到最优解.
dfs1找的是,当前这个点在满足L和S的情况下能找到的深度最小的祖父,top记录的是这个点的最远祖父下标。
dfs2找的就是答案了。若一个点是叶子结点,那么ans必然+1,如果儿子的最优解是儿子本身,那么也+1.在dfs2中,除非sta[ne]==ne,其它时候的sta都是暂定的。举个例子:
5 3 12
1 1 1 10 1
1 2 2 4
在找5的时候,sta[5]=2,sta[4]=2,但是到2的时候他会发现sta[3]=1,是更优解。
5 4 12
1 1 10 1 1
1 2 2 4这种情况的时候,找到2的时候sta[4]就比sta[3]更优了,所以这种做法是找当前点的最优解。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+5;
struct node
{
    int to,next;
}e[N];
int head[N],cnt,fa[N][20],top[N],dep[N];
int n,L;
ll S,w[N],sum[N];
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
void bfs()
{
    fa[1][0]=1;
    dep[1]=0;
    queue<int>Q;
    Q.push(1);
    while(!Q.empty())
    {
        int u,v;
        u=Q.front();
        Q.pop();
        for(int i=1;i<=16;i++)
            fa[u][i]=fa[fa[u][i-1]][i-1];
        for(int i=head[u];~i;i=e[i].next)
        {
            v=e[i].to;
            if(v==fa[u][0])
                continue;
            dep[v]=dep[u]+1;
            fa[v][0]=u;
            Q.push(v);
        }
    }
}
void dfs1(int x,int f)
{
    sum[x]=sum[f]+w[x];
    dep[x]=dep[f]+1;
    top[x]=x;
    int dis=L;
    for(int i=16;i>=0;i--)
    {
        int gf=fa[top[x]][i];
        if(!gf)
            continue;
        if((1<<i)>=dis)
            continue;
        if(sum[x]-sum[gf]+w[gf]>S)
            continue;
        top[x]=gf;
        dis-=(1<<i);
    }
    for(int i=head[x];~i;i=e[i].next)
        dfs1(e[i].to,x);
}
int ans,sta[N];
void dfs2(int x)
{
    int maxn=-1;
    for(int i=head[x];~i;i=e[i].next)
    {
        int ne=e[i].to;
        dfs2(ne);
        if(sta[ne]==ne)
            continue;
        if(maxn==-1||dep[sta[ne]]<dep[maxn])
            maxn=sta[ne];
    }
    if(maxn==-1)
        maxn=top[x],ans++;
    sta[x]=maxn;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d%lld",&n,&L,&S);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&w[i]);
        if(w[i]>S)
            return 0*printf("-1\n");
    }
    int x;
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&x);
        add(x,i);
    }
    bfs();
    dfs1(1,0);
    dfs2(1);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/84109844
今日推荐