题意:
有两棵树,他们的叶子结点通过一些设备一一联合。这两棵树的根节点都会供电,通过节点和边传导。问你在让所有设备都能发光的条件下,最多能去掉几条边。
题解:
有很简单的做法。。
因为去掉一些边一定是去掉某个节点及子树上的边,那么我们只需要做出每个点所掌握的设备的区间范围,看看去掉它的收益是多少,因为有两棵树,所以一段区间,一定有一边不会被删掉,只会删掉花费较大的那一边。
#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;
}