zoukankan      html  css  js  c++  java
  • RXD, tree and sequence IN HDU6065

      解这道题绕了好多弯路。。。先是把"depth of the least common ancestor"这句话忽视掉,以为是最深点与最浅点的深度差;看到某人题解(的开头)之后发现自己理解错误,修改思路。结果又是绕好多弯路。构造了一个式子dp[i,j]其中i是前几个点,j是切分的段数。一直以为转移是整段转移(如果段是(1,5),直接dp[5,j]=dp[0,j-1]+val(1,5)),但是发现时间复杂度又过高,o(nk*n),之后改变了下思路,发现这题的整段真正有用的是最小深度那个核。

      题意是把一串n排列切分成k段,让里面的数计算这些对应结点的最近公共祖先深度,之后求这个最小深度总和。如(1) (5 2 4 3),第1段是1的深度,第2段是min( dep(lca(5,2)) , dep(lca(2,4)) , dep(lca(4,3)) ),其中的核就是最小的那个deplca。

      dp转移不需转移整段,可以空转移,只要保证加上那个核的权值之后跳到下一段就行,这样转移步幅小了很多(1~2),dp次数也降为o(nk)

      dp[i,j]=dp[i-1,j](把i这个点当成对答案无关的跳过)dp[i-1,j-1](把i这个点当成对答案有关的核转移)dp[i-2,j-1](把i-1和i的最近公共祖先当成对答案有关的核转移)

      这里的代码很无耻地借鉴了autsky-jadek的。。。

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #define min(a,b) (a<b?a:b)
    using namespace std;
    typedef pair<int,int> Point;
    const int N=300005;
    int a[N],head[N],to[N<<1],nxt[N<<1],lca[N],fa[N],dep[N],ans[N],arc[N];
    bool vis[N];
    int n,k,u,v,en;
    int dp[N+100000];
    
    void addedge(int u,int v)
    {
        to[en]=v;
        nxt[en]=head[u];
        head[u]=en++;
    }
    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!=-1;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;
        if(u!=0 && vis[u-1])
            lca[u-1]=ans[find_(u-1)];
        if(u!=n-1 && vis[u+1])
            lca[u]=ans[find_(u+1)];
    }
    int main()
    {
        int tmp,i;
        while(scanf("%d%d",&n,&k)!=EOF)
        {
            en=0;
            memset(vis,0,sizeof(vis));
            memset(dep,0,sizeof(dep));
            memset(head,-1,sizeof(head));
            memset(dp,0,sizeof(dp));
            for(i=0;i<n;i++)
            {
                scanf("%d",&tmp);
                arc[tmp]=fa[i]=i;
            }
            for(i=1;i<n;i++)
            {
                scanf("%d%d",&u,&v);
                addedge(arc[u],arc[v]);addedge(arc[v],arc[u]);
            }
            LCA(arc[1],1);
            for(i=0;i<n-1;++i)
                lca[i]=dep[lca[i]];
            for(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,dp[(i-1)*(k+1)+j-1]+dep[i-1]);
                    if(i-2>=0&&j-1>=0&&j-1<=i-2)
                        nowans=min(nowans,dp[(i-2)*(k+1)+j-1]+lca[i-2]);
                    if(j<=i-1)
                        nowans=min(nowans,dp[(i-1)*(k+1)+j]);
                    dp[i*(k+1)+j]=nowans;
                }
            }
            printf("%d
    ",dp[n*(k+1)+k]);
        }
        return 0;
    }
    View Code

       tarjan离线,全局求祖先,顺带把相邻数字全查了

  • 相关阅读:
    web全栈第四讲:后端框架express.js初步体验。
    web全栈第三讲:Angular单页面应用
    Web第六讲:HTML基础
    关于命令模式的一点意见
    黑猫白猫读《大话设计模式》
    排序二叉树的实现和我的一个数据结构设计
    《算法与数据结构C语言描述》优先队列
    《算法与数据结构C语言描述》里的农夫过河
    读《算法与数据结构c语言描述》
    《算法与数据结构C语言描述》里的求多项达式值
  • 原文地址:https://www.cnblogs.com/dgutfly/p/7275201.html
Copyright © 2011-2022 走看看