关闭

HDU 6065 RXD, tree and sequence DP 减少转移情况

标签: DP
535人阅读 评论(1) 收藏 举报
分类:

给一颗有根树,根节点为1,再给定一个排列,长度为n,要求将排列切分成K段,定义每段的价值为该排列所有点及两两点之间lca中最浅节点的深度。要求输出K段区间所有可能的价值和中的最小值。n*K<=3e5。

解法:

很明显可以往dp方向思考。定义dp[i][j]为前i位切分成j段的价值和的最小值。在列出转移方程前,先说明观察到的若干性质:

性质1. 定义“一段排列所有点及两两点之间lca中最浅节点的深度”为T,当在排列末尾加上一个节点ai的时候,只需要求一下ai-1与ai的lca,再与之前的lca比较谁的深度小,维护深度的最小值即可。

这个性质很好拿数学归纳法证明:

a) 朴素情况是只有一个点,T就是自己的深度。两个点,T就是它们lca的深度。

b)假设长度为k的区间K可以这么维护T,定义该区间最浅深度的节点为tnode,加入一个新的节点ak+1时只有两种情况:

i) 该节点位于tnode为根的子树内,tnode依然是最浅的节点;

ii) 该节点位于tnode为根的子树外,则与区间K中任意一点求lca,等价于与tnode求lca,即lca(ak,ak+1)=lca(tnode,ak+1)。故依然用该方法可以维护长度为k+1区间的T值。

证毕。

性质2. 处理出相邻点间lca深度之后,比如 7 4 5 6 3 9 10,若最优切分方式里 4 与 3 在不同区间里,4 与 3 之间的任何数,即 5 6,划分给 3 区间或者 4 区间,都不会影响最终答案。 

性质3. 区间末尾增加新的节点时,价值T一定是不增的。

细细思考这些性质之后,,,,就有:

在区间新加入一个点时,只需要按2种情况转移新加入的点即可:

a) 将该点放到前一个区间里,dp[i][j]=dp[i-1][j];

b) 将该点放到下一个区间里,dp[i][j]=dp[i-1][j-1]+depth[j] 或者 dp[i][j]=dp[i-2][j-1]+depth[lca(i-1,i)]。

这些情况全拿min维护一下就行啦,一切都放到dp数组里去转移了。。。

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=300005;
int n,K,a[maxn],f[maxn],dep[maxn],dp[3][maxn],lca[maxn];
vector<pii> ask[maxn];
vector<int> G[maxn];
void init() {
    for (int i=1;i<=n;++i) {
        f[i]=i;
        G[i].clear();
        ask[i].clear();
    }
    for (int i=1;i<n;++i) {
        ask[a[i]].push_back(pii(i+1,a[i+1]));
        ask[a[i+1]].push_back(pii(i+1,a[i]));
    }
    memset(dep,0,(n+1)*sizeof dep[0]);
}
int F(int x) {
    return x==f[x]?x:f[x]=F(f[x]);
}
inline void U(int a,int b) {
    f[F(b)]=F(a);
}
void dfs(int u,int d) {
    dep[u]=d;
    for (int i=0;i<(int)ask[u].size();++i) {
        int j=ask[u][i].second,p=ask[u][i].first;
        if (dep[j])
            lca[p]=dep[F(j)];
    }
    for (int i=0;i<(int)G[u].size();++i) {
        int v=G[u][i];
        if (dep[v])
            continue;
        dfs(v,d+1);
        U(u,v);
    }
}
int main()
{
    while (scanf("%d%d",&n,&K)==2) {
        for (int i=1;i<=n;++i)
            scanf("%d",&a[i]);
        init();
        for (int i=0;i<n-1;++i) {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1,1);
        memset(dp[0],0x3f,(n+1)*sizeof dp[0][0]);
        dp[0][0]=0;
        for (int i=1;i<=n;++i) {
            dp[i%3][0]=0;
            for (int j=1;j<=K;++j) {
                dp[i%3][j]=min(dp[(i-1)%3][j],dp[(i-1)%3][j-1]+dep[a[i]]);
                if (i>=2)
                    dp[i%3][j]=min(dp[i%3][j],dp[(i+1)%3][j-1]+lca[i]);
            }
        }
        printf("%d\n",dp[n%3][K]);
    }
    return 0;
}


0
0
查看评论

HDU-6065 RXD, tree and sequence(dp+LCA)

传送门:HDU-6065 题意:根节点为1的有根树,给定一个排列,长度为n,要求将排列切分成K段,定义每段的价值为该排列中两两之间的公共祖先中的最浅深度。要求总价值最小 题解: 首先列出几个性质: 性质1.所有节点的公共祖先的深度一定是两两节点之间的公共祖先的最浅深度 性质2.如果某一段的前x个数的...
  • qq_31759205
  • qq_31759205
  • 2017-08-04 23:20
  • 461

HDU 6065 RXD, tree and sequence 分析+01背包

//给你个树,序列,分隔 序列k段, 求 每段lca 深度之和最小。 /* 求[i,j]的LCA 我们可以通过求[i,j-1] and j的LCA ; deep(lca) <=deep[i,j]; deep(lca) =min(deep(i,j-1),lca(j,j-1...
  • vvv_557
  • vvv_557
  • 2017-08-13 10:01
  • 152

HDU 3516 Tree Construction (dp+四边形不等式优化)

这题是个区间DP。。当时根本没想到。。。 设dp[i][j]为将区间i到j内的所有节点连接的最短边权和。 那么这棵树肯定是有两子树构成。方程便为:dp[i][j] = min(dp[i][j],dp[i][k] + dp[k+1][j] + dis(i,j))。 然后用四边形不等式。 ...
  • qq_26572969
  • qq_26572969
  • 2015-07-30 11:45
  • 264

2017多校第3场 HDU 6065 RXD, tree and sequence LCA,DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6065 题意:给一颗有根树,根节点为1,再给定一个排列,长度为n,要求将排列切分成K段,定义每段的价值为该排列所有点及两两点之间lca中最浅节点的深度。要求输出K段区间所有可能的价值和中的最小值。n...
  • just_sort
  • just_sort
  • 2017-08-06 09:08
  • 262

解题报告:HDU_6061 RXD and functions NTT

题目链接 题意及官方题解: 思路: 先感谢Q巨指点Qrz... 先求得系数式: 拆开组合数: 把系数提取出来稍作变换: 整理一下: 得到: 然后就可以直接进行NTT了。。 代码; #include const int mod = 998244353; cons...
  • qq_32570675
  • qq_32570675
  • 2017-08-02 10:27
  • 927

[HDU6065] RXD, tree and sequence

Problem LinkDescription    给定一棵有nn个节点并且以1为根的树,根的深度为1。给定1n1 n的Solution    首先我们要知道一个重要的性质:对于一个连续块,它最终的LCALCA一定可以...
  • ccf15068475758
  • ccf15068475758
  • 2017-08-10 19:41
  • 237

RXD and math(HDU 6063 快速幂)

RXD is a good mathematician. One day he wants to calculate: ∑i=1nkμ2(i)×⌊nki−−−√⌋ output the answer module 109+7. 1≤n,k≤1018 μ(n)=1(n=1) μ(n)=(...
  • luyehao1
  • luyehao1
  • 2017-08-01 21:09
  • 599

HDU6065 RXD, tree and sequence (DP+LCA)

HDU6065 RXD, tree and sequence (DP+LCA)
  • SidneyBill
  • SidneyBill
  • 2017-09-07 16:03
  • 78

HDU 5909 Tree Cutting (点分治+树形DP|FWT+树形DP)

题目描述传送门题目大意:给出一棵树,求异或和为[0..m-1]的非空连通子图的个数。题解1FWT+树形DP f[i][j]f[i][j]表示以i为根异或和为j的连通子树的个数(注意必须是i的子树中) f[x][jf[x][j^k]=f[x][jk]=f[x][j^k]+f[x][j]∗f[son...
  • clover_hxy
  • clover_hxy
  • 2017-05-25 10:15
  • 244

HDU 6065 RXD, tree and sequence(在线倍增LCA+CDQ分治+离线tarjan-LCA+dp)

Description 给出一棵n个节点的树和一个1~n的排列,要求把该排列分成k个连续的段,使得每段点在树上的LCA深度之和最小 Input 多组用例,每组用例首先输入两个整数n和k,之后输入一个1~n的排列,最后n-1行每行两个整数u和v表示u和v之间有一条树边,以文件尾结束输入 (1&...
  • V5ZSQ
  • V5ZSQ
  • 2017-08-07 09:44
  • 276
    个人资料
    • 访问:14202次
    • 积分:818
    • 等级:
    • 排名:千里之外
    • 原创:65篇
    • 转载:0篇
    • 译文:0篇
    • 评论:13条
    文章分类
    最新评论