CF1153D Serval and Rooted Tree

这也能dp??

 

不dp也没法做了

 

设sz[x]是x子树中叶子节点的个数,f[x]是把1 ~ sz[x]这个排列放入到x子树的叶子节点上,x节点能取到的最大值

 

当x为叶子时,f[x] = sz[x] = 1

当x不是叶子时,sz[x]=\sum sz[v],f[x]就得分别考虑取最大值和取最小值的情况

1)当x取最大值时,考虑某个儿子v对x的转移,对于一个儿子v,它要占掉sz[v]-f[v]个值,也就是说向其中放入sz[v]个数,从小到大后sz[v]-f[v]个数是x取不到的

那么这时候就发现f[x]的取值只与某个儿子v有关,也就是把1~sz[x]从小到大后sz[v]个数放入到v子树中,这时x在v上取的值是sz[x]-(sz[v]-f[v])

所以得到转移方程f[x]=max(sz[x]-(sz[v]-f[v]))

2)当x取最小值时,就得需要考虑所有的儿子从而保证取得最小值够大,那么怎么考虑呢

正如上述所说,对于一个儿子v,它要占掉sz[v]-f[v]个值,然后把所有儿子的sz[v]-f[v]都加起来,就得到取不到的值的个数C,这时就从大到小把sz[x]~1填入C个,剩下的就是儿子能取到的数

因为要在儿子中选最小,设S为x的儿子个数,所以还要再往前填S个数,其中填入的第S个数就是f[x]的取值

转移方程 f[x]=sz[x]-\sum (sz[v]-f[v]) - S + 1 = sz[x]-\sum (sz[v]-f[v]+1) +1

 

上面的方程手玩几个例子就得到了

 

 

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define db double
#define rep(x,a,b) for(int x=(a);x<=(b);x++)
#define per(x,a,b) for(int x=(a);x>=(b);x--)
#define reP(x,a,b) for(int x=(a);x<(b);x++)
#define Per(x,a,b) for(int x=(a);x>(b);x--)
#define scf(a) scanf("%d",&a)
#define scfll(a) scanf("%lld",&a)
#define scfdb(a) scanf("%lf",&a)
#define ptf(a) printf("%d",a)
#define ptfll(a) printf("%lld",a)
#define ptfsp(a) printf("%d ",a)
#define ptfllsp(a) printf("%lld ",a)
#define pli(a,b) make_pair(a,b)
#define pb push_back
#define el puts("")
#define FS first
#define SE second
#define PI acos(-1)
/*ios::sync_with_stdio(false);
freopen("in.txt","r",stdin);
freopen("1.out","w",stdout);*/
using namespace std;
const ll mod=998244353;
const int maxn=3e5+5;
int f[maxn],sz[maxn],d[maxn],a[maxn];
vector<int>g[maxn];
void dfs(int x,int fa){
    if(d[x]==1){
        sz[x]=1;
        f[x]=1;
        return;
    }
    reP(i,0,g[x].size()){
        int v=g[x][i];
        if(v==fa) continue;
        dfs(v,x);
        sz[x]+=sz[v];
    }
    if(a[x]==1){
        reP(i,0,g[x].size()){
            int v=g[x][i];
            if(v==fa) continue;
            f[x]=max(f[x],sz[x]-(sz[v]-f[v]));
        }
    }
    else{
        int sum=0;
        reP(i,0,g[x].size()){
            int v=g[x][i];
            if(v==fa) continue;
            sum+=(sz[v]-f[v]+1);
        }
        f[x]=sz[x]-sum+1;
    }
}
int main(){
    int n;scf(n);
    rep(i,1,n) scf(a[i]);
    rep(i,2,n){
        int x;scf(x);
        g[x].push_back(i);
        g[i].push_back(x);
        d[i]++;d[x]++;
    }
    dfs(1,0);
    cout<<f[1];
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值