首页 > 其他分享 >P5558 心上秋

P5558 心上秋

时间:2023-10-14 09:12:13浏览次数:23  
标签:心上 dp1 P5558 昭君 lca 序列 最长 dp

Description

竟宁元年(前33年)正月,昭君出塞前一晚。

画师跌跌撞撞地来到昭君居住的宫殿。

 听说北国的那座城池
 被冬雪覆了终日
 等到故人长诀渐行渐远
 转眼已隔两世
            ——《心上秋》

如果再也不能相见的话,画师想着,他想给昭君留下些什么。

他想把他的画笔送给昭君。

昭君的宫殿里有 \(N\) 个房间,有 \(N-1\) 条道路连接这些房间。

画师现在在宫殿的入口大厅 \(S\) 房间,他依稀记得,昭君的房间在 \(T\) 号。

窗外,风雨大作,宫内忽暗忽明,一个人影也没有。

画家走进晦暗的通道,每条通道里的墙壁上都画有若干片枫叶,这是之前昭君让画师画的。昭君说,她特别喜欢秋天,尤其喜欢秋天的枫叶。

  并肩长谈过多少往事,恍然间黄昏已至    ——《心上秋》

通道内晦暗无比,画师想点亮通道内备好的蜡烛,他记得昭君有个习惯,每个通道内的蜡烛数量就是墙上枫叶的数量。昭君若想点燃一条通道内的蜡烛,就会全部点燃,此时昭君认为这条通道已被点亮,并且不会再点亮任何枫叶数少于这条通道的通道

这应该是最后一次来到这个地方了,画师想着,他要按昭君的习惯,走到昭君的房间。

现在画师想知道,他从宫殿大厅 \(S\) 走到昭君房间 \(T\),最多可以点亮多少通道。

一句话题意

给一棵树,带边权。多次询问,每次询问一条路径上的最长不下降子序列的长度。

\(N\le 30000,M\le 300000\)。边权 \(\in[1,5]\)。

Solution

注意到边权极小,考虑从此突破。

对于一个序列,我们可以枚举起始值和终止值,然后求出满足值在起始值和终止值之间的最长不下降子序列。假如我们求出了若干序列的上述答案,那么我们就可以将题目所求路径分成若干序列,枚举序列交界处的值,那么有转移 \(dp_{i,x}=\max(dp_{i-1,y}+g_{i,y,x})\)。其中 \(dp_{i,x}\) 表示求完前 \(i\) 个序列,当前终止值为 \(x\) 的最长不下降子序列,\(g_{i,x,y}\) 表示对于序列 \(i\),起始值是 \(y\),终止值是 \(x\) 的最长不下降子序列。转移本质就是枚举当前序列的起始值是什么,而当前序列的起始值就是上一个序列的终止值。

但问题是对于不同的询问,预先要求的序列也是不同的。那么如何找到一些序列,使其可以去表示所有的路径呢?显然可以用树剖或者倍增。这里考虑使用倍增。

改变一下上面 \(g\) 数组的定义。设 \(g_{x,i,a,b}\) 表示从节点 \(x\) 开始,向上走 \(2^{i-1}\) 条边,起始值为 \(a\),终止值为 \(b\) 的最长不下降子序列。\(g\) 同样可以用倍增来得到,只需要枚举交界处的值是什么即可。\(g_{u,i,a,b}=\max(g_{u,i-1,a,c}+g_{v,i-1,c,b})\)(\(v\) 表示 \(u\) 的第 \(2^{i-1}\) 级祖先)。

但是 \(x\to lca\to y\) 的过程中,\(x\to lca\) 是向上走没错,但是 \(lca\to y\) 是向下走,但我们只能维护向上的值。因此我们还需要求出从 \(y\) 向上走的最长不上升子序列,求法和求最长不下降子序列是类似的,在此不过多赘述。这里将最长不下降记为 \(g1\),最长不上升记为 \(g2\)。

至此,我们就已完成了本题。首先我们要预处理出 \(g1\) 和 \(g2\)。然后对于每条路径,从 \(x\) 或 \(y\) 向 \(lca\) 跳的时候,将若干 \(2\) 的次方长度的路径看作若干个序列,用上文求 \(dp\) 的做法转移(此时 \(dp\) 可以设为 \(dp_{x,i}\) 表示到了节点 \(x\),值为 \(i\) 的最长不下降(或上升)子序列)。最后枚举 \(lca\) 处的值是多少,\(ans=\max(dp^{x\to lca}_{lca,i}+dp^{y\to lca}_{lca,i})\)。

注意一些小优化,比如说在求 \(lca\) 的时候就可以同时求 \(dp\),\(g1\) 和 \(g2\) 数组可以合并称一个数组 \(g\),用 \(a\) 和 \(b\) 的大小关系表示不下降还是不上升。时间复杂度 \(\mathcal O(5^3N\log N+5^2M\log N)\),但远远达不到。目前是最优解。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 30005
using namespace std;
int n,m,tot,ans,f[N][20],dep[N],dp1[N][6],dp2[N][6],g[N][20][6][6];
struct node {int to,next,head,val;}a[N<<1];
int read()
{
	int res=0;char ch=getchar();
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch-'0'),ch=getchar();
	return res;
}
void add(int x,int y,int z)
{
	a[++tot].to=y;a[tot].val=z;a[tot].next=a[x].head;a[x].head=tot;
	a[++tot].to=x;a[tot].val=z;a[tot].next=a[y].head;a[y].head=tot;
}
void dfs(int x,int fa)
{
	f[x][0]=fa;dep[x]=dep[fa]+1;
	for (int i=a[x].head;i;i=a[i].next)
	{
		int y=a[i].to,z=a[i].val;
		if (y==fa) continue;
		for (int z1=1;z1<=z;++z1)
			for (int z2=z;z2<=5;++z2)
			{
				g[y][0][z1][z2]=1;
				g[y][0][z2][z1]=1;
			}
		dfs(y,x);
	}
}
int LCA(int x,int y)
{	
	for (int i=1;i<=5;++i)
		dp1[x][i]=dp2[y][i]=0;
	if (dep[x]>dep[y])
	{
        for (int i=14;i>=0;--i)
        {
            if (dep[f[x][i]]>=dep[y]) 
            {
            	for (int j=1;j<=5;++j)
            		dp1[f[x][i]][j]=0;
                for (int j=1;j<=5;++j)
                    for (int k=j;k<=5;++k)
                        dp1[f[x][i]][k]=max(dp1[f[x][i]][k],dp1[x][j]+g[x][i][j][k]);
                x=f[x][i];
            }
        }
    }
    else
    {
        for (int i=14;i>=0;--i)
        {
            if (dep[f[y][i]]>=dep[x]) 
            {
            	for (int j=1;j<=5;++j)
            		dp2[f[y][i]][j]=0;
                for (int j=1;j<=5;++j)
                    for (int k=1;k<=j;++k)
                        dp2[f[y][i]][k]=max(dp2[f[y][i]][k],dp2[y][j]+g[y][i][j][k]);
                y=f[y][i];
            }
        }
    }
	if (x==y) return x;
	for (int i=14;i>=0;--i)
	{
		if (f[x][i]!=f[y][i]) 
		{
			for (int j=1;j<=5;++j)
				dp1[f[x][i]][j]=dp2[f[y][i]][j]=0;
			for (int j=1;j<=5;++j)
				for (int k=1;k<=5;++k)
				{
					if (k>=j) dp1[f[x][i]][k]=max(dp1[f[x][i]][k],dp1[x][j]+g[x][i][j][k]);
					if (k<=j) dp2[f[y][i]][k]=max(dp2[f[y][i]][k],dp2[y][j]+g[y][i][j][k]);
				}
			x=f[x][i];y=f[y][i];
		}	
	}
	for (int j=1;j<=5;++j)
		dp1[f[x][0]][j]=dp2[f[y][0]][j]=0;
	for (int j=1;j<=5;++j)
		for (int k=1;k<=5;++k)
		{
			if (k>=j) dp1[f[x][0]][k]=max(dp1[f[x][0]][k],dp1[x][j]+g[x][0][j][k]);
			if (k<=j) dp2[f[y][0]][k]=max(dp2[f[y][0]][k],dp2[y][j]+g[y][0][j][k]);
		}
	return f[x][0];
}
int main()
{
	n=read();
	for (int i=1;i<n;++i)
	{
		int x,y,z;
		x=read();y=read();z=read();
		add(x,y,z);
	}
	dfs(1,0);
	for (int i=0;i<14;++i)
	{
		bool flag=false;
		for (int u=2;u<=n;++u)
		{
			int v=f[u][i];
			if (!f[v][i]) continue;
			f[u][i+1]=f[v][i];
			flag=true;
			for (int x=1;x<=5;++x)
				for (int z=x+1;z<=5;++z)
					for (int y=x;y<=z;++y)
					{
						g[u][i+1][x][z]=max(g[u][i+1][x][z],g[u][i][x][y]+g[v][i][y][z]);
						g[u][i+1][z][x]=max(g[u][i+1][z][x],g[u][i][z][y]+g[v][i][y][x]);
					}
			for (int x=1;x<=5;++x)
				g[u][i+1][x][x]=g[u][i][x][x]+g[v][i][x][x];
		}
		if (!flag) break;
	}
	m=read();
	for (int i=1;i<=m;++i)
	{
		int x,y;
		x=read();y=read();
		int lca=LCA(x,y);
		ans=0;
		for (int i=1;i<=5;++i)
			ans=max(ans,dp1[lca][i]+dp2[lca][i]);
		printf("%d\n",ans);
	}
	return 0;
}

标签:心上,dp1,P5558,昭君,lca,序列,最长,dp
From: https://www.cnblogs.com/Livingston/p/17763677.html

相关文章

  • 国庆倒计时、无心上班?看这里。。。(建议收藏)
    计算机视觉研究院专栏作者:Edison_G“过了星期三,翻过一座山;到了星期五,再熬一下午!”。在大厂工作的一种心态,但是今天不同,再坚持一天,就是7天小长假,每个人都安耐不住了,但是,在你无心工作的时候,还是可以阅读今天的分享,干货满满!公众号ID|ComputerVisionGzq提前祝大家国庆节快乐!在长假之前,我......
  • LangChain集成中心上线
    LangChain框架介绍LangChain创建于2022年10月,是围绕LLMs(大语言模型)建立的一个框架,LLMs使用机器学习算法和海量数据来分析和理解自然语言,GPT3.5、GPT4是LLMs最先进的代表,国内百度的文心一言、阿里的通义千问也属于LLMs。LangChain自身并不开发LLMs,它的核心理念是为各种LLMs实现通......
  • k8s 能做到限制pod在节点的指定cpu核心上运行吗?用--cpuset 方式实现,请给出一个具体案
    在Kubernetes中,可以使用--cpuset方式来限制Pod在节点的指定CPU核心上运行。这可以通过在Pod的yaml文件中设置容器启动命令来实现。具体地,我们可以在容器的启动命令中使用--cpuset选项来指定需要运行的CPU核心。下面是一个典型的使用--cpuset选项的Pod的yaml文件示例:apiVersion:......
  • 中电资讯-杭州银行新一代互联网核心上线!
    11月24日晚9点至25日早6点,杭州银行中一群人守在电脑前,目不转睛地盯着屏幕上滚动的代码。此时,他们正在经历一个重要的关键时刻,杭州银行金融级云原生技术平台及分布式核心业务......
  • 安科瑞能耗管理系统解决方案在数据中心上的应用
    安科瑞陈盼1、概述  随着碳达峰、碳中和成为政府工作主要任务,数据中心作为能耗密集,用能情况较为复杂的大型建筑,有效的降低能源消耗,减少能源成本,避免用能过程中的“跑冒滴......