【洛谷】P5024 保卫王国

前言

传送门

  很多人写了题解了,我就懒得写了,推荐一篇博客

  那就分享一下我的理解吧(说得好像有人看一样

  对于每个点都只有选与不选两种情况,所以直接用倍增预处理出来两种情况的子树之内,子树之外的最值,最终答案以拼凑的方式得出

  如果这个题要修改权值的话就真的只能用动态dp了(好像还有那个什么全局平衡树

  我真的觉得去年出题人只是想出一个倍增,结果被动态dp干了(Ark:出题人真的只是想出一个动态dp

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100005;
const long long inf=1ll<<60;
long long f[maxn][30],g[maxn][30],F[maxn][30][2][2];char ch[10];
int n,m,ecnt,v[maxn<<1],nx[maxn<<1],dep[maxn],info[maxn],fa[maxn][30];
void add(int u1,int v1){nx[++ecnt]=info[u1];info[u1]=ecnt;v[ecnt]=v1;}
void dfs1(int x,int fath)
{
    dep[x]=dep[fa[x][0]=fath]+1;
    for(int i=info[x];i;i=nx[i])if(v[i]!=fath)
    dfs1(v[i],x),f[x][0]+=f[v[i]][1],f[x][1]+=min(f[v[i]][0],f[v[i]][1]);
}
void dfs2(int x)
{
    for(int i=info[x];i;i=nx[i])if(v[i]!=fa[x][0])
    g[v[i]][0]=g[x][1]+f[x][1]-min(f[v[i]][0],f[v[i]][1]),
    g[v[i]][1]=min(g[v[i]][0],g[x][0]+f[x][0]-f[v[i]][1]),dfs2(v[i]);
}
long long solve(int x,int a,int y,int b)
{
    if(dep[x]<dep[y])swap(x,y),swap(a,b);
    long long tx[2]={inf,inf},ty[2]={inf,inf},nwx[2],nwy[2];
    tx[a]=f[x][a];ty[b]=f[y][b];
    for(int i=25;i>=0;i--)if((dep[x]-dep[y])&(1<<i))
    {
        nwx[0]=nwx[1]=inf;
        for(int u=0;u<=1;u++)for(int v=0;v<=1;v++)
        nwx[u]=min(nwx[u],tx[v]+F[x][i][v][u]);
        tx[0]=nwx[0],tx[1]=nwx[1];x=fa[x][i];
    }
    if(x==y)return nwx[b]+g[y][b];
    for(int i=25;i>=0;i--)if(fa[x][i]!=fa[y][i])
    {
        nwx[0]=nwx[1]=nwy[0]=nwy[1]=inf;
        for(int u=0;u<=1;u++)for(int v=0;v<=1;v++)
        nwx[u]=min(nwx[u],tx[v]+F[x][i][v][u]),nwy[u]=min(nwy[u],ty[v]+F[y][i][v][u]);
        tx[0]=nwx[0],tx[1]=nwx[1];x=fa[x][i];ty[0]=nwy[0],ty[1]=nwy[1];y=fa[y][i];
    }
    int lca=fa[x][0]=fa[y][0];
    long long ret1=g[lca][0]+f[lca][0]-f[x][1]-f[y][1]+tx[1]+ty[1],
    ret2=g[lca][1]+f[lca][1]-min(f[x][0],f[x][1])-min(f[y][0],f[y][1])+min(tx[0],tx[1])+min(ty[0],ty[1]);
    return min(ret1,ret2);
}
int main()
{
    scanf("%d%d%s",&n,&m,ch+1);for(int i=1;i<=n;i++)scanf("%lld",&f[i][1]);
    for(int i=1,u1,v1;i<n;i++)scanf("%d%d",&u1,&v1),add(u1,v1),add(v1,u1);
    dfs1(1,0);dfs2(1);memset(F,0x3f,sizeof F);
    for(int i=1;i<=n;i++)
    F[i][0][1][1]=f[fa[i][0]][1]-min(f[i][0],f[i][1]),F[i][0][0][0]=inf,
    F[i][0][0][1]=f[fa[i][0]][1]-min(f[i][0],f[i][1]),F[i][0][1][0]=f[fa[i][0]][0]-f[i][1];
    for(int k=1;k<=25;k++)for(int i=1;i<=n;fa[i][k]=fa[fa[i][k-1]][k-1],i++)
    for(int u=0;u<=1;u++)for(int v=0;v<=1;v++)for(int w=0;w<=1;w++)
    F[i][k][u][v]=min(F[i][k][u][v],F[i][k-1][u][w]+F[fa[i][k-1]][k-1][w][v]);
    for(int i=1,a,b,x,y;i<=m;i++)
    {
        scanf("%d%d%d%d",&x,&a,&y,&b);
        if(a==0&&b==0&&(fa[x][0]==y||fa[y][0]==x))puts("-1");
        else printf("%lld\n",solve(x,a,y,b));
    }
}

猜你喜欢

转载自www.cnblogs.com/firecrazy/p/11756163.html