• bzoj4446:[Scoi2015]小凸玩密室


    传送门

    神仙题吧,很有东西
    看了题解才会做的
    先提取有用信息:
    1、这个密室是一棵有n个节点的完全二叉树
    2、在点灯的过程中,要保证任意时刻所有被点亮的灯泡必须连通
    3、在点亮一个灯泡后必须先点亮其子树所有灯泡才能点亮其他灯泡
    所以get到信息
    1、树高严格(logn)
    2、点亮的灯泡组成一个联通块
    3、点亮一个灯泡后一定是往儿子走
    然而我依然不会,借助题解才设出了状态
    (f[i][j][0])表示第一次点第(i)个节点,点亮完(i)的子树后点亮(i)的第(j)个祖先的最小花费
    (f[i][j][1])表示第一次点第(i)个节点,点亮完(i)的子树后点亮(i)的第(j)个祖先的另一个儿子的最小花费(就是(i)节点所在子树的兄弟节点)
    预处理出每个节点的所有祖先,
    然后考虑怎么转移,分三种情况
    1、没有儿子的,算出它到它的所有祖先的花费
    2、只有左儿子或只有右儿子的,只能往左或者右走
    3、有两个儿子的,分情况讨论一下
    由于第一次点的点不确定,所以要枚举一下,然后一直往上走就行了,碰到有2个儿子的判断一下,就行了
    方程我就不写了,这位大佬方程写的很详细传送门
    时间复杂度(O(nlogn))

    千万别看我代码,去看那些非递归转移的吧,我的代码已经魔改的看不得了

    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define int long long
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=2e5+10;
    int n,a[maxn],b[maxn],l[maxn],r[maxn],g[maxn][20],f[maxn][20][2],dep[maxn],ans;
    void prepare(int x)
    {
    	int now=x,tot=1;
    	while(now)now=g[now][1],tot++,g[x][tot]=now;
    	if(l[x])g[l[x]][1]=x,dep[l[x]]=dep[x]+b[l[x]-1],prepare(l[x]);
    	if(r[x])g[r[x]][1]=x,dep[r[x]]=dep[x]+b[r[x]-1],prepare(r[x]);
    }
    void dfs(int x)
    {
    	if(!l[x]&&!r[x])
    	{
    		int now=x,las;
    		for(rg int i=1;i<20;i++)
    		{
    			las=now,now>>=1;
    			if(!now)break;
    			f[x][i][0]=(dep[x]-dep[now])*a[now];
    			if(l[now]&&r[now])
    			{
    				if(l[now]!=las)f[x][i][1]=(dep[x]+dep[l[now]]-2*dep[now])*a[l[now]];
    				else f[x][i][1]=(dep[x]+dep[r[now]]-2*dep[now])*a[r[now]];
    			}
    			else f[x][i][1]=1e18;
    		}
    	}
    	else 
    	{
    		if(l[x]&&!r[x])
    		{
    			dfs(l[x]);
    			f[x][0][0]=1e18;
    			f[x][0][0]=min(f[x][0][0],f[l[x]][0][0]+(dep[l[x]]-dep[x])*a[l[x]]);
    			for(rg int i=1;i<20;i++)
    			{
    				if(!g[x][i])break;
    				f[x][i][0]=f[x][i][1]=1e18;
    				f[x][i][0]=min(f[x][i][0],f[l[x]][i+1][0]+(dep[l[x]]-dep[x])*a[l[x]]);
    				f[x][i][1]=min(f[x][i][1],f[l[x]][i+1][1]+(dep[l[x]]-dep[x])*a[l[x]]);
    			}
    		}
    		else if(r[x]&&!l[x])
    		{
    			dfs(r[x]);
    			f[x][0][0]=1e18;
    			f[x][0][0]=min(f[x][0][0],f[r[x]][0][0]+(dep[r[x]]-dep[x])*a[r[x]]);
    			for(rg int i=1;i<20;i++)
    			{
    				if(!g[x][i])break;
    				f[x][i][0]=f[x][i][1]=1e18;
    				f[x][i][0]=min(f[x][i][0],f[r[x]][i+1][0]+(dep[r[x]]-dep[x])*a[r[x]]);
    				f[x][i][1]=min(f[x][i][1],f[r[x]][i+1][1]+(dep[r[x]]-dep[x])*a[r[x]]);
    			}
    		}
    		else 
    		{
    			dfs(l[x]),dfs(r[x]);
    			f[x][0][0]=1e18;
    			f[x][0][0]=min(f[x][0][0],f[l[x]][1][1]+(dep[l[x]]-dep[x])*a[l[x]]+f[r[x]][0][0]);
    			f[x][0][0]=min(f[x][0][0],f[r[x]][1][1]+(dep[r[x]]-dep[x])*a[r[x]]+f[l[x]][0][0]);
    			for(rg int i=1;i<20;i++)
    			{
    				if(!g[x][i])break;
    				f[x][i][0]=f[x][i][1]=1e18;
    				f[x][i][0]=min(f[x][i][0],f[l[x]][1][1]+(dep[l[x]]-dep[x])*a[l[x]]+f[r[x]][i+1][0]);
    				f[x][i][0]=min(f[x][i][0],f[r[x]][1][1]+(dep[r[x]]-dep[x])*a[r[x]]+f[l[x]][i+1][0]);
    				f[x][i][1]=min(f[x][i][1],f[l[x]][1][1]+(dep[l[x]]-dep[x])*a[l[x]]+f[r[x]][i+1][1]);
    				f[x][i][1]=min(f[x][i][1],f[r[x]][1][1]+(dep[r[x]]-dep[x])*a[r[x]]+f[l[x]][i+1][1]);
    			}
    		}
    	}
    }
    signed main()
    {
    	read(n);
    	for(rg int i=1;i<=n;i++)read(a[i]);
    	for(rg int i=1;i<n;i++)
    	{
    		read(b[i]);
    		if(!l[(i+1)/2])l[(i+1)/2]=i+1;
    		else r[(i+1)/2]=i+1;
    	}
    	prepare(1),dfs(1);ans=f[1][0][0];
    	for(rg int i=2;i<=n;i++)
    	{
    		int las,now=i,val=f[i][1][0];
    		while(g[now][1]!=1)
    		{
    			las=now,now=g[now][1];
    			if(l[now]&&r[now])
    			{
    				if(las!=l[now])val+=(dep[l[now]]-dep[now])*a[l[now]]+f[l[now]][2][0];
    				else val+=(dep[r[now]]-dep[now])*a[r[now]]+f[r[now]][2][0];
    			}
    			else 
    			{
    				if(las!=i)val+=(dep[las]-dep[now])*a[now];
    				val+=(dep[now]-dep[g[now][1]])*a[g[now][1]];
    			}
    		}
    		las=now,now=g[now][1];
    		if(l[now]&&r[now])
    		{
    			if(las!=l[now])val+=(dep[l[now]]-dep[now])*a[l[now]]+f[l[now]][0][0];
    			else val+=(dep[r[now]]-dep[now])*a[r[now]]+f[r[now]][0][0];
    		}
    		else if(las!=i)val+=(dep[las]-dep[now])*a[now];
    		ans=min(ans,val);
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    箭头函数1
    变量结构赋值
    警惕32位程序在MethodImplOptions.Synchronized在x64机器上的同步缺陷[z]
    ListView的BeginUpdate()和EndUpdate()作用[z]
    如何用命令将本地项目上传到git[z]
    C# 两个datatable中的数据快速比较返回交集或差集[z]
    C# DataTable抽取Distinct数据(不重复数据)[z]
    【Thread】CountdownEvent任务并行[z]
    C#多线程--信号量(Semaphore)[z]
    VS2015一新建项目就出现未将对象引用设置到对象的实例怎么办?[z]
  • 原文地址:https://www.cnblogs.com/lcxer/p/10501773.html
Copyright © 2020-2023  润新知