【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即可,f(i,j)表示前i个数,划分成j段的最优值。

只有三种决策,要么不取,继承f(i-1,j),要么将其自己作为某段的最小值,转移自f(i-1,j-1),要么将其与其前位的lca作为某段的最小值,转移自f(i-2,j-1)。

如果用tarjan预处理相邻的lca的话,复杂度是O(n*K)。

比std不知道高明到哪里去了。234ms。

UPDATE: 靠,换成动态求lca以后,明明多了一个log,变成140ms了。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int,int> Point;
vector<vector<int> >f;
vector<Point>ask[300005];
int a[300005],head[300005],to[600005],nxt[600005],lca[300005];
int n,k,u,v,en;
void add(int u,int v)
{
    nxt[++en]=head[u];
    head[u]=en;
    to[en]=v;
}
int FA[300005],ans[300005],dep[300005];
bool VIS[300005];
int find(int x){
	return x==FA[x] ? x : FA[x]=find(FA[x]);
}
void LCA(int u,int nowdeep)
{
    ans[u]=u;
    dep[u]=nowdeep;
    for(int i=head[u];i;i=nxt[i]) if(!dep[to[i]])
      {
        LCA(to[i],nowdeep+1);
        int f1=find(u),f2=find(to[i]);
        FA[f1]=f2;
        ans[find(u)]=u;
      }
    VIS[u]=true;
    for(int i=0;i<ask[u].size();i++)
      if(VIS[ask[u][i].first]){
      	lca[ask[u][i].second]=ans[find(ask[u][i].first)];
      }
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        f.assign(n+1,vector<int>(k+1,0));
        memset(VIS,0,sizeof(VIS));
        for(int i=1;i<=n;++i){
        	ask[i].clear();
        	FA[i]=i;
        }
        en=0;
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
        }
        for(int i=2;i<=n;++i){
        	ask[a[i-1]].push_back(make_pair(a[i],i));
        	ask[a[i]].push_back(make_pair(a[i-1],i));
        }
        for(int i=1;i<n;++i)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        LCA(1,1);
        for(int i=2;i<=n;++i)
            lca[i]=dep[lca[i]];
        for(int i=1;i<=n;++i)
        {
            int top=min(i,k);
            for(int j=0;j<=top;++j)
            {
                int nowans=99999999;
                if(j>0&&i>0)
                    nowans=min(nowans,f[i-1][j-1]+dep[a[i]]);
                if(i-2>=0&&j-1>=0&&j-1<=i-2)
                    nowans=min(nowans,f[i-2][j-1]+lca[i]);
                if(j<=i-1)
                    nowans=min(nowans,f[i-1][j]);
                f[i][j]=nowans;
            }
        }
        printf("%d\n",f[n][k]);
        for(int i=1;i<=n;++i)
        {
        	dep[i]=0;
            head[i]=0;
        }
    }
    return 0;
}
时间: 2024-10-11 21:30:57

【Tarjan】【LCA】【动态规划】【推导】hdu6065 RXD, tree and sequence的相关文章

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/Others)Total Submission(s): 234    Accepted Submission(s): 82 Problem Description RXD has a rooted tree T with size n, the root ID is 1, with the dep

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 个数只有三种可能.

POJ 3694 Network (tarjan + LCA)

题目链接:http://poj.org/problem?id=3694 题意是给你一个无向图n个点,m条边,将m条边连接起来之后形成一个图,有Q个询问,问将u和v连接起来后图中还有多少个桥. 首先用tarjan标记点的low和dfn值,那么u和v相连的边是桥的条件是dfn[u] < low[v](说明v与u不在一个连通分量里面,v无法通过回溯到达u点,画个图模拟会清楚).那么bridge[v]++表示u与v相连的边是桥(若是标记bridge[u]++,则最后的答案可能会出错,亲测).要是u和v相

cdoj 92 Journey tarjan/lca 树上点对距离

Journey Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/92 Description Bob has traveled to byteland, he find the N cities in byteland formed a tree structure, a tree structure is very special structure, there is exa

hdu 5286 How far away ? tarjan/lca

How far away ? Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2586 Description There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How f

POJ - 3694 Network(tarjan+lca)

题意:给出一个无相图,然后q次新增加边,问在添加边的过程中桥的数目当且仅当无向边(u,v)为树枝的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u-v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥思路:首先我们知道在给定一张图之后,不断添加边,桥的数目只会减少而不是增加tarjan的使用就是缩点,将一个连通分量缩成一个点,那么那个连通分量中的边都不会是桥同时缩完点之后我们就会发现,桥其实就是新形成的树的边在添加的过程中,如果是在连通分量内就

(tarjan LCA) hdu 2586

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6727    Accepted Submission(s): 2497 Problem Description There are n houses in the village and some bidirectional roads connecting

tarjan LCA模板

1 #include<cstdio> 2 #include<iostream> 3 #define MN 300000 4 using namespace std; 5 int n,m,w[MN],cnt,h[MN],q[MN]; 6 int s[MN],t[MN],fa[MN],dis[MN],a[MN]; 7 bool vis[MN]; 8 struct edge{int to,next;}e[MN*8]; 9 void ins(int *h,int u,int v){e[++

[动态规划][树形dp]Bichrome Tree

题目描述 We have a tree with N vertices. Vertex 1 is the root of the tree, and the parent of Vertex i (2≤i≤N) is Vertex Pi.To each vertex in the tree, Snuke will allocate a color, either black or white, and a non-negative integer weight.Snuke has a favor