【洛谷】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));
}
}