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\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/lcxer/p/10501773.html