HDU 6065 RXD, tree and sequence (LCA+DP)

Posted dwtfukgv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6065 RXD, tree and sequence (LCA+DP)相关的知识,希望对你有一定的参考价值。

题意:给定上一棵树和一个排列,然后问你把这个排列分成m个连续的部分,每个部分的大小的是两两相邻的LCA的最小深度,问你最小是多少。

析:首先这个肯定是DP,然后每个部分其实就是里面最小的那个LCA的深度。很容易知道某个区间的值肯定是 [li, li+1] .. [ri-1, ri]这些区间之间的一个,并且我们还可以知道,举个例子,1 2 3 4  5 6 如果知道分成两部分 其中 2 和 6 是最优的,那么中间的 3 4 5 ,这三个数其实属于哪个区间都无所谓,所以对于第 i 个数只有三种可能。

dp[i[j] 表示前 i 个数分成 j 个区间

第一种:它自己属于单独的区间,dp[i][j] = min{ dp[i-1][j-1] + deep[a[i]] }

第二种:它和前面那个数属于一个区间,dp[i][j] = min{ dp[i-2][j-1] + deep[lca(a[i], a[i-1])] }

第三种:它对任何区间都没有贡献,那么无所谓了 dp[i][j] = min{ dp[i-1][j] }

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#define debug() puts("++++");
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define sz size()
#define pu push_up
#define pd push_down
#define cl clear()
//#define all 1,n,1
#define FOR(i,x,n)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.txt", "r", stdin)
#define freopenw freopen("out.txt", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 3e5 + 20;
const int maxm = 100 + 10;
const ULL mod = 10007;
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, -1, 0, 1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c) {
  return r >= 0 && r < n && c >= 0 && c < m;
}

struct Edge{
  int to, next;
};
Edge edge[maxn<<1];
int head[maxn], cnt;

void addEdge(int u, int v){
  edge[cnt].to = v;
  edge[cnt].next = head[u];
  head[u] = cnt++;
}

int a[maxn];
int dp[3][maxn];
int dep[maxn], p[20][maxn];
void dfs(int u, int fa, int d){
  dep[u] = d;
  p[0][u] = fa;
  for(int i = head[u]; ~i; i = edge[i].next){
    int v = edge[i].to;
    if(v == fa)  continue;
    dfs(v, u, d + 1);
  }
}

void init(){
  ms(p, -1);
  dfs(1, -1, 1);
  FOR(k, 0, 19)  for(int v = 1; v <= n; ++v){
    if(p[k][v] < 0)  p[k+1][v] = -1;
    else p[k+1][v] = p[k][p[k][v]];
  }
}

int LCA(int u, int v){
  if(dep[u] > dep[v])  swap(u, v);
  for(int k = 0; k < 20; ++k)
    if(dep[v] - dep[u] >> k & 1)  v = p[k][v];
  if(u == v)  return u;
  for(int k = 19; k >= 0; --k)
    if(p[k][u] != p[k][v]){
      u = p[k][u];
      v = p[k][v];
    }
  return p[0][u];
}

int lca[maxn];

int main(){
  while(scanf("%d %d", &n, &m) == 2){
    for(int i = 1; i <= n; ++i)  scanf("%d", a + i);
    ms(head, -1);  cnt = 0;
    for(int i = 1; i < n; ++i){
      int u, v;
      scanf("%d %d", &u, &v);
      addEdge(u, v);
      addEdge(v, u);
    }
    init();  ms(dp, INF);  lca[1] = dep[a[1]];
    for(int i = 2; i <= n; ++i)  lca[i] = dep[LCA(a[i], a[i-1])];
    dp[0][0] = dp[1][0] = dp[2][0] = 0;
    for(int i = 1; i <= n; ++i){
      int t = min(i, m);
      for(int j = 1; j <= t; ++j){
        dp[i%3][j] = min(dp[(i-1)%3][j-1] + dep[a[i]], dp[(i-1)%3][j]);
        if(i > 1)  dp[i%3][j] = min(dp[i%3][j], dp[(i-2)%3][j-1] + lca[i]);
      }
    }
    printf("%d\n", dp[n%3][m]);
  }
  return 0;
}

  

以上是关于HDU 6065 RXD, tree and sequence (LCA+DP)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6060 RXD and dividing(dfs 思维)

hdu 6060 RXD and dividing

hdu 6063 RXD and math

hdu6060 RXD and dividing 贪心

HDU 6060 RXD and dividing(LCA)

HDU 6060 17多校3 RXD and dividing(树+dfs)