Codeforces 1263 F Economic Difficulties —— dp

This way

题意:

有两棵树,他们的叶子结点通过一些设备一一联合。这两棵树的根节点都会供电,通过节点和边传导。问你在让所有设备都能发光的条件下,最多能去掉几条边。

题解:

有很简单的做法。。
因为去掉一些边一定是去掉某个节点及子树上的边,那么我们只需要做出每个点所掌握的设备的区间范围,看看去掉它的收益是多少,因为有两棵树,所以一段区间,一定有一边不会被删掉,只会删掉花费较大的那一边。

#include<bits/stdc++.h>
using namespace std;
const int N=2e3+5;
struct node{
    int to,next;
}e[N*2];
int cnt,head[N];
void add(int x,int y){
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
int lef[N],dp[N],siz[N],sta[N],en[N];
struct point{
    int l,r,v;
    bool operator< (const point& a)const {
        if(r==a.r)return l<a.l;
        return r<a.r;
    }
};
vector<point>vec;
void dfs(int x){
    siz[x]=1;
    if(lef[x])sta[x]=en[x]=lef[x];
    for(int i=head[x];~i;i=e[i].next){
        dfs(e[i].to);
        if(!sta[x])sta[x]=sta[e[i].to];
        else sta[x]=min(sta[x],sta[e[i].to]);
        if(!en[x])en[x]=en[e[i].to];
        else en[x]=max(en[x],en[e[i].to]);
        siz[x]+=siz[e[i].to];
    }
    vec.push_back({sta[x]-1,en[x],siz[x]-(x==1)});
}
int main()
{
    int n,m,k;
    scanf("%d",&k);
    for(int t=1;t<=2;t++){
        scanf("%d",&n);
        memset(head,-1,sizeof(head));
        memset(lef,0,sizeof(lef));
        memset(sta,0,sizeof(sta));
        memset(en,0,sizeof(en));

        cnt=0;
        int x;
        for(int i=2;i<=n;i++)scanf("%d",&x),add(x,i);
        for(int i=1;i<=k;i++)scanf("%d",&x),lef[x]=i;
        dfs(1);
    }

    sort(vec.begin(),vec.end());
    for(auto i: vec)
        dp[i.r]=max(dp[i.r],dp[i.l]+i.v);
    printf("%d\n",dp[k]);
    return 0;
}

发布了530 篇原创文章 · 获赞 31 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/104091474