Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 234    Accepted Submission(s): 82

Problem Description
RXD has a rooted tree 5
Input
There are several test cases, please keep reading until EOF.
For each test case, the first line consists of 2 integer b, means a tree edge.
It is guaranteed that the edges would form a tree.
There are 6 test cases.
Output
For each test case, output an integer, which means the answer.
Sample Input
6 3 4 6 2 5 1 3 1 2 2 3 3 4 4 5 4 6
Sample Output
6
Source

 【题意】给你一棵树,然后给你树的节点编号的一种排列,然后要你将这个序列分成非空的k份,对于每一份求lca的深度,然后累加,   求和最小。

 【分析】首先得想到区间lca的一个性质,对于区间[i,j],他们的lca肯定是lca[i,i+1],lca[i+1,i+2],...lca[j-1,j]中的某一个,也就是说,对于某一个区间,决定lca的只有某相邻的两个数。然后在这个序列中,对于某一个数,他有三种存在状态。第一,它存在于某个区间,但是这个区间的lca不是由它决定的。第二,它一个数本身作为一份。第三,它和它左边的数的lca作为某一份的lca。然后dp[i][j]表示前i个数分成j段的最小答案,对于上面三种情况分别对应三个方程

dp[i][j]=min(dp[i][j],dp[i-1][j]);
dp[i][j]=min(dp[i][j],dp[i-1][j-1]+dep[a[i]]);
dp[i][j]=min(dp[i][j],dp[i-2][j-1]+lca[i]);

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 5e5+50;
const int M = 16000009;
const int mod = 1e9+7;
const double pi= acos(-1.0);
typedef pair<int,int>pii;
int n,k,ans;
int dep[N],fa[N][20];
int a[N],lca[N];
vector<int>edg[N];
void dfs(int u,int f){
    fa[u][0]=f;
    for(int i=1;i<20;i++){
        fa[u][i]=fa[fa[u][i-1]][i-1];
    }
    for(int v : edg[u]){
        if(v==f)continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
}
int LCA(int u,int v){
    int U=u,V=v;
    if(dep[u]<dep[v])swap(u,v);
    for(int i=19;i>=0;i--){
        if(dep[fa[u][i]]>=dep[v]){
            u=fa[u][i];
        }
    }
    if(u==v)return (u);
    for(int i=19;i>=0;i--){
        if(fa[u][i]!=fa[v][i]){
            u=fa[u][i];v=fa[v][i];
        }
    }
    return (fa[u][0]);
}

int main(){
    while(~scanf("%d%d",&n,&k)){
        int dp[n+50][k+50];
        met(dp,inf);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),edg[i].clear();
        for (int i=1,u,v;i<n;i++){
            scanf("%d%d",&u,&v);
            edg[u].pb(v);
            edg[v].pb(u);
        }
        dep[1]=1;
        dfs(1,0);
        dp[0][0]=0;
        for(int i=2;i<=n;i++){
            int m = LCA(a[i-1],a[i]);
            lca[i]=dep[m];
        }
        for(int i=1;i<=n;i++){
            for(int j=0;j<=min(i,k);j++){
                if(i-1>=j)dp[i][j]=min(dp[i][j],dp[i-1][j]);
                if(j>0)dp[i][j]=min(dp[i][j],dp[i-1][j-1]+dep[a[i]]);
                if(j>0&&i>=2&&j-1<=i-2)dp[i][j]=min(dp[i][j],dp[i-2][j-1]+lca[i]);
            }
        }
        printf("%d\n",dp[n][k]);
    }
    return 0;
}

 

相关文章: