OwO http://acm.hdu.edu.cn/showproblem.php?pid=6065

  (2017 Multi-University Training Contest - Team 3 - 1010)

  首先,一个连续段的LCA就是每相邻两个点的LCA的最小值

  证明:

    假设有一段区间s1~sn,称这段区间为S,他们的LCA是U,那么U必然存在多个后继,这里为了方便假设U存在2个后继,若后继不止2个,可类似得到结论

    那么这两个后继就有对应的2个子树A,B,由于S的LCA是U,所以A,B中均有S的元素。那么设S中在子树A中的元素为a1~ap,在子树B中的元素为b1~bq。

    不妨设s1存在于A中。对于si,如果si+1和si不同在A或不同在B中,那么对于si和si+1,他们的LCA就是u

    那么,如果不存在相邻两点他们LCA为u的话,对于任意si,si和si+1他们同在A或同在B,由于s1在A,所以s1~sn全在A中,那么区间S中就没有B的元素,则S的LCA就不是U,矛盾。

  那么可以先预处理出每两个相邻点的LCA

  然后声明一个dp数组dp[i][j]的意义为,从1~i分成j段的最小答案。

  把P分成k个连续段P1,P2…Pn,则设这些段中LCA深度最小的相邻两点对为pair1,pair2,pair3…pairn,那么我们可以把它们当做由这些pair领头的序列(开头可以出现一段不计入答案的序列)(如果这些段只有一个点那么就不变)

  这样的dp[i][j]就可以由以下3种方式推导过来

  1.dp[i][j]=dp[i-1][j] 相当于把第j段扩展下去,由于最小两对是开头,所以不用更新其值

  2.dp[i][j]=dp[i-2][j-1]+depth[LCA(P[i-1],P[i])] 就是从分成j-1段那里递推来,然后了个开头(开头为2两个相邻点,这两个相邻点当做第j段LCA深度最小的相邻点)

  3.dp[i][j]=dp[i-1][j-1]+depth[P[i]] 也是从分成j-1段那里递推过来,只不过开头是一个点,

  这样dp[n][k]就是答案   

  (思路来自某位大佬 orz)

  

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h> using namespace std; const int M=3e5+55;
const int MAXN = 340044;
const int MAXQ = 500010; int F[MAXN];//需要初始化为-1 int find(int x)
{
if(F[x] == -1)return x;
return F[x] = find(F[x]);
} void bing(int u,int v)
{
int t1 = find(u);
int t2 = find(v);
if(t1 != t2)
F[t1] = t2;
} bool vis[MAXN];//访问标记
int ancestor[MAXN];//祖先 struct Edge
{
int to,next;
}edge[MAXN*2]; int head[MAXN],tot; void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} struct Query
{
int q,next;
int index;//查询编号
}query[MAXQ*2];
int answer[MAXQ];//存储最后的查询结果,下标0~Q-1
int h[MAXQ];
int tt;
int Q; void add_query(int u,int v,int index)
{
query[tt].q = v;
query[tt].next = h[u];
query[tt].index = index;
h[u] = tt++;
query[tt].q = u;
query[tt].next = h[v];
query[tt].index = index;
h[v] = tt++;
} void init()
{
tot = 0;
memset(head,-1,sizeof(head));
tt = 0;
memset(h,-1,sizeof(h));
memset(vis,false,sizeof(vis));
memset(F,-1,sizeof(F));
memset(ancestor,0,sizeof(ancestor));
} void LCA(int u)
{
ancestor[u] = u;
vis[u] = true;
for(int i = head[u];i != -1;i = edge[i].next)
{
int v = edge[i].to;
if(vis[v])continue;
LCA(v);
bing(u,v);
ancestor[find(u)] = u;
}
for(int i = h[u];i != -1;i = query[i].next)
{
int v = query[i].q;
if(vis[v])
{
answer[query[i].index] = ancestor[find(v)];
}
}
} int dep[M];
int n,k;
int s[M];
int ans;
vector<vector<int> > dp; void getdep(int rt,int pa,int depth)
{
int i,j,v;
dep[rt]=depth;
for(i=head[rt];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(v==pa)
continue;
getdep(v,rt,depth+1);
}
} void solve()
{
int i,j,tmp;
getdep(1,-1,1);
for(i=0;i<=n;i++)
dp[i][0]=0;
for(i=1;i<=n;i++)
for(j=1;j<=min(i,k);j++)
{
tmp=1e9+7;
if(i-1>=1)
tmp=min(tmp,dp[i-2][j-1]+dep[answer[i-1-1]]);
// cout<<i<<' '<<j<<' '<<tmp<<endl;
tmp=min(tmp,dp[i-1][j-1]+dep[s[i]]);
if(i-1>=j)
tmp=min(tmp,dp[i-1][j]);
// cout<<i<<' '<<j<<' '<<tmp<<endl;
dp[i][j]=tmp;
// cout<<i<<' '<<j<<' '<<tmp<<endl;
}
ans=dp[n][k];
cout<<ans<<endl;
} int main()
{
int i,j;
int u,v;
while(scanf("%d%d",&n,&k)!=EOF)
{
dp.assign(n+2,vector<int>(k+2,1e9+7));
init();
for(i=1;i<=n;i++)
scanf("%d",&s[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
Q=n-1;
for(i=0;i<Q;i++)
add_query(s[1+i],s[1+i+1],i);
LCA(1);
solve();
}
return 0;
}

  

  

hdu 6065 RXD, tree and sequence的更多相关文章

  1. HDU 6065 RXD, tree and sequence (LCA DP)

    RXD, tree and sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java ...

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

    题意:给定上一棵树和一个排列,然后问你把这个排列分成m个连续的部分,每个部分的大小的是两两相邻的LCA的最小深度,问你最小是多少. 析:首先这个肯定是DP,然后每个部分其实就是里面最小的那个LCA的深 ...

  3. RXD, tree and sequence IN HDU6065

    解这道题绕了好多弯路...先是把"depth of the least common ancestor"这句话忽视掉,以为是最深点与最浅点的深度差:看到某人题解(的开头)之后发现自 ...

  4. 【Tarjan】【LCA】【动态规划】【推导】hdu6065 RXD, tree and sequence

    划分出来的每个区间的答案,其实就是连续两个的lca的最小值. 即5 2 3 4 这个区间的答案是min(dep(lca(5,2)),dep(lca(2,3),dep(lca(3,4)))). 于是dp ...

  5. HDU 5513 Efficient Tree

    HDU 5513 Efficient Tree 题意 给一个\(N \times M(N \le 800, M \le 7)\)矩形. 已知每个点\((i-1, j)\)和\((i,j-1)\)连边的 ...

  6. ※数据结构※→☆非线性结构(tree)☆============二叉树 顺序存储结构(tree binary sequence)(十九)

    二叉树 在计算机科学中,二叉树是每个结点最多有两个子树的有序树.通常子树的根被称作“左子树”(left subtree)和“右子树”(right subtree).二叉树常被用作二叉查找树和二叉堆或是 ...

  7. HDU 4925 Apple Tree(推理)

    HDU 4925 Apple Tree 题目链接 题意:给一个m*n矩阵种树,每一个位置能够选择种树或者施肥,假设种上去的位置就不能施肥,假设施肥则能让周围果树产量乘2.问最大收益 思路:推理得到肯定 ...

  8. 2017 多校3 hdu 6061 RXD and functions

    2017 多校3 hdu 6061 RXD and functions(FFT) 题意: 给一个函数\(f(x)=\sum_{i=0}^{n}c_i \cdot x^{i}\) 求\(g(x) = f ...

  9. HDU 4871 Shortest-path tree 最短路 + 树分治

    题意: 输入一个带权的无向连通图 定义以顶点\(u\)为根的最短路生成树为: 树上任何点\(v\)到\(u\)的距离都是原图最短的,如果有多条最短路,取字典序最小的那条. 然后询问生成树上恰好包含\( ...

随机推荐

  1. 小白学习django第一站-环境配置

    Django简单来说就是用Python开发的一个免费开源的Web框架 使用Django,使你能够以最小的代价构建和维护高质量的Web应用. 开搞!!! 工具准备: linux(ubuntu) + py ...

  2. 并不对劲的P5589

    题目大意 有\(n\)(\(n\leq 10^9\))个数:\(1,2,...,n\),每次操作是随机取一个没被删除的数\(x\),并删去\(x,x^2,x^3,...\). 求期望几次删完所有数. ...

  3. DVWA之SQL注入演练(low)

    1.设置 把安全等级先调整为low,让自己获得点信心,免得一来就被打脸. 2.测试和分析页面的功能       这里有一个输入框 根据上面的提示,输入用户的id.然后我们输入之后,发现它返回了关于这个 ...

  4. 使用SQL语句查询Elasticsearch索引数据

    Elasticsearch 的官方查询语言是 Query DSL,存在毕竟有存在的道理,存在即合理.SQL 作为一个数据库查询语言,它语法简洁,书写方便而且大部分服务端程序员都清楚了解和熟知它的写法. ...

  5. 大数据学习(2)- export、source(附带多个服务器一起启动服务器)

    linux环境中, A=1这种命名方式,变量作用域为当前线程 export命令出的变量作用域是当前进程及其子进程. 可以通过source 脚本,将脚本里面的变量放在当前进程中 附带自己写的tomcat ...

  6. 单元操作和仓储模式 repository+unitOfWork

    仓储和工作单元模式是用来在数据访问层和业务逻辑层之间创建一个抽象层.应用这些模式,可以帮助用来隔离你的程序在数据存储变化. 在数据源层和业务层之间增加一个repository层进行协调,有如下作用:1 ...

  7. python获取文件及文件夹大小

    Python3.3下测试通过 获取文件大小 使用os.path.getsize函数,参数是文件的路径 获取文件夹大小 import os from os.path import join, getsi ...

  8. 如何判断kbmMWClientQuery当前记录的增改状态?

    有朋友问我,客户端使用了kbmMWClientQuery,对其进行了编辑后,对于指定的记录,如何判断是否是增加的记录,或者是被修改后的记录? 下面这个函数,返回aDataSet当前记录的修改状态: f ...

  9. 第四篇.python的基础

    目录 第四篇.python基础01 1. 变量 2. 常量 3. python变量内存管理 4. 变量的三个特征 5. 花式赋值 6. 注释 7. 数据类型基础 8. 数字类型 9. 字符串类型 10 ...

  10. beego注解路由不刷新(不生效)

    本文主要说明本人在使用beego的注解路由时不生效问题 背景: 1.按照官网进行注解路由配置,第一次设置路由,完全正确,注解路由可用. 2.修改路由注释后,发现swagger页面并未有对应的更新 3. ...