zoukankan      html  css  js  c++  java
  • hdu 6065 RXD, tree and sequence

      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;
    }
    

      

      

  • 相关阅读:
    hash表学习笔记
    【学习笔记-集合】HashMap 源码浅析
    java 同步
    学习SpringBoot了
    记录一些好的 学习网站
    Idea 的页面布局设定,tomcat及普通web项目设定
    Spring 札记
    java面试题(基础+非基础)[不定期更新]
    maven 使用
    ant 生成报告时报错,Errors while applying transformations: Fatal error during transformation
  • 原文地址:https://www.cnblogs.com/FxxL/p/7274279.html
Copyright © 2011-2022 走看看