C75 动态DP+树增 P8820 [CSP-S 2022] 数据传输
视频链接:261 动态DP+树增 P8820 [CSP-S 2022] 数据传输_哔哩哔哩_bilibili
#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())); }