1 条题解

  • 0
    @ 2025-10-8 16:59:41

    C75 动态DP+树增 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()));
    }
    
    • 1

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

    信息

    ID
    1985
    时间
    3000ms
    内存
    1024MiB
    难度
    9
    标签
    递交数
    11
    已通过
    4
    上传者