C75 动态DP+树增 P8820 [CSP-S 2022] 数据传输

视频链接:261 动态DP+树增 P8820 [CSP-S 2022] 数据传输_哔哩哔哩_bilibili

 

 

 

 

 

 

 

Luogu P8820 [CSP-S 2022] 数据传输

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

int read(){
  int s=0,b=1;char c;
  while((c=getchar())>'9'||c<'0') if(c=='-') b=-1;
  while(c>='0'&&c<='9') s=s*10+(c^48),c=getchar();
  return s*b;
}
#define LL long long
#define F(i,a,b) for(int i=a;i<=b;i++)
const int N=200005;
const LL inf=1e18;
int n,m,K,v[N],s[N];  //s:儿子最小权
int cmp(int x,int y){return v[x]<v[y];}
vector<int> e[N];     //邻接点
int dep[N],fa[N][19]; //树增
struct matrix{LL g[3][3];};
matrix operator*(matrix a,matrix b){
  matrix c;
  for(int i=0;i<=2;i++)
    for(int j=0;j<=2;j++) c.g[i][j]=inf;
  for(int i=0;i<=2;i++)
    for(int j=0;j<=2;j++)
      for(int k=0;k<=2;k++)
      c.g[i][j]=min(c.g[i][j],a.g[i][k]+b.g[k][j]);
  return c;
}
matrix I,B[N],U[N][19],D[N][19];
//I:单位矩阵 B:转移矩阵 U:矩阵上乘积 D:矩阵下乘积

void init(){ //初始化I,B
  for(int i=0;i<=2;i++)
    for(int j=0;j<=2;j++)
      I.g[i][j]=(i==j?0:inf);
  if(K==1) for(int i=1;i<=n;i++){
    for(int j=0;j<=2;j++)
      for(int k=0;k<=2;k++) B[i].g[j][k]=inf;
    B[i].g[0][0]=v[i];
  }
  if(K==2) for(int i=1;i<=n;i++){
    for(int j=0;j<=2;j++)
      for(int k=0;k<=2;k++) B[i].g[j][k]=inf;
    B[i].g[0][0]=B[i].g[0][1]=v[i];
    B[i].g[1][0]=0;
  }
  if(K==3) for(int i=1;i<=n;i++){
    for(int j=0;j<=2;j++) B[i].g[0][j]=v[i];
    B[i].g[1][0]=B[i].g[2][1]=0;
    B[i].g[1][2]=B[i].g[2][0]=B[i].g[2][2]=inf;
    B[i].g[1][1]=s[i];
  }
}
void dfs(int x,int f){ //树增fa,dep,U,D
  fa[x][0]=f; dep[x]=dep[f]+1;
  U[x][0]=D[x][0]=B[x];
  //fa[x][i]:距离x为2^i的祖先
  //U[x][i]:从x到2^i的点的矩阵上乘积
  //D[x][i]:从x到2^i的点的矩阵下乘积
  for(int i=1;i<=18;i++){
    fa[x][i]=fa[fa[x][i-1]][i-1],
    U[x][i]=U[x][i-1]*U[fa[x][i-1]][i-1],
    D[x][i]=D[fa[x][i-1]][i-1]*D[x][i-1];  
  }
  for(int y:e[x]) if(y!=f) dfs(y,x);
}
matrix LCA(int x,int y){ //树增LCA求逆序积
  matrix sx=I,sy=I;
  if(dep[x]<dep[y]) //因x上跳了一层
    sy=B[y],y=fa[y][0];
  //x先大步后小步向上跳,直到与y同层
  for(int i=18;i>=0;i--)
    if(dep[fa[x][i]]>=dep[y])
      sx=D[x][i]*sx,
      x=fa[x][i];
  if(x==y) return sy*B[y]*sx;
  //x,y一起向上跳,直到lca的下面
  for(int i=18;i>=0;i--)
    if(fa[x][i]!=fa[y][i])
      sx=D[x][i]*sx,sy=sy*U[y][i],
      x=fa[x][i],y=fa[y][i];
  return sy*B[y]*B[fa[y][0]]*B[x]*sx;
}
LL query(int x,int y){ //查询
  if(dep[x]<dep[y]) swap(x,y);
  matrix f=I; f.g[0][0]=v[x];
  matrix ans=LCA(fa[x][0],y)*f;
  return ans.g[0][0];
}
int main(){
  n=read(),m=read(),K=read();
  for(int i=1;i<=n;i++) v[i]=read();
  for(int i=1;i<n;i++){
    int a=read(),b=read();
    e[a].push_back(b),e[b].push_back(a);
  }
  for(int i=1;i<=n;i++)sort(e[i].begin(),e[i].end(),cmp);
  for(int i=1;i<=n;i++)s[i]=v[e[i][0]]; //儿子最小权
  init();
  dfs(1,0);
  while(m--) printf("%lld\n",query(read(),read()));
}

 

posted @ 2023-12-05 20:23  董晓  阅读(188)  评论(0编辑  收藏  举报