CF1000G Two-Paths
題目大意:給你一棵樹,其中點(diǎn)上和邊上都有值。定義2-Path為經(jīng)過(guò)一條邊最多兩次的路徑,價(jià)值為經(jīng)過(guò)點(diǎn)的權(quán)值加和-經(jīng)過(guò)邊權(quán)值*該邊經(jīng)過(guò)次數(shù)。4e5組詢問(wèn),每次詢問(wèn)樹上連接x,y兩點(diǎn)的2-Path的最大價(jià)值。
先說(shuō)一句:
機(jī)房中認(rèn)為圖畫的最好:https://blog.csdn.net/lleozhang/article/details/83659914
題解:
一道狀態(tài)比較多的樹形dp。
dp1:記錄x點(diǎn)子樹內(nèi)從x到x的最大2-Path的價(jià)值-x的值。
dp2:記錄從fa[x]到fa[x]不經(jīng)過(guò)x且不經(jīng)過(guò)fa[fa[x]]的最大2-Path價(jià)值-fa[x]的值。
dp3:記錄從fa[x]到fa[x]不經(jīng)過(guò)x的任意兒子的2-Path的價(jià)值-x的值。
(描述比較惡心,見圖)
(圖也比較惡心)
紅色的邊和涂黑的未知物體都要取。
然后還有比較大眾的ds1:記錄x到根的點(diǎn)權(quán)之和,和ds2:記錄x到根的邊權(quán)之和。
還要求一下每個(gè)點(diǎn)到根節(jié)點(diǎn)經(jīng)過(guò)點(diǎn)的dp2之和。
dfsO(n)搞dp,詢問(wèn)O(nlogn)。
比描述和圖片更惡心的代碼:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 300050 #define Q 400050 #define ll long long int n,q,hed[N],cnt; struct EG {int to,nxt;ll val; }e[2*N]; void ae(int f,int t,ll v) {e[++cnt].to = t;e[cnt].val = v;e[cnt].nxt = hed[f];hed[f] = cnt; } ll a[N]; int dep[N],fa[N][25]; ll ds1[N],ds2[N],E[N]; void dfs1(int u,int f) {dep[u]=dep[f]+1;for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(to==f)continue;fa[to][0]=u;E[to]=e[j].val;ds1[to]=ds1[u]+a[to];ds2[to]=ds2[u]+e[j].val;dfs1(to,u);} } int get_lca(int x,int y) {if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];if(x==y)return x;for(int i=20;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];return fa[x][0]; } ll dp1[N],dp2[N]; bool vis[N]; void dfs(int u) {for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(to==fa[u][0])continue;dfs(to);if(dp1[to]+a[to]-2ll*e[j].val>=0){dp1[u]+=dp1[to]+a[to]-2ll*e[j].val;vis[to]=1;}}for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(to==fa[u][0])continue;if(!vis[to])dp2[to]=dp1[u];else dp2[to]=dp1[u]-(dp1[to]+a[to]-2ll*e[j].val);} } ll dp3[N],sum2[N]; void Dfs(int u) {sum2[u]+=dp2[u];for(int j=hed[u];j;j=e[j].nxt){int to = e[j].to;if(to==fa[u][0])continue;sum2[to]+=sum2[u];dp3[to]=max(0ll,dp3[u]+1ll*a[u]+dp2[to]-2ll*e[j].val);Dfs(to);} } ll sol(int x,int y) {if(dep[x]>dep[y])swap(x,y);int lca = get_lca(x,y);if(x==lca){return dp3[x]+dp1[y]+sum2[y]-sum2[x]+(ds1[x]+ds1[y]-ds1[lca]-ds1[fa[lca][0]])-(ds2[x]+ds2[y]-2ll*ds2[lca]);}else{int ffx = x,ffy = y;for(int i=20;i>=0;i--){if(dep[fa[ffx][i]]>dep[lca])ffx=fa[ffx][i];if(dep[fa[ffy][i]]>dep[lca])ffy=fa[ffy][i];}return dp1[x]+dp1[y]+sum2[x]+sum2[y]-sum2[ffx]-sum2[ffy]+dp3[lca]+dp2[ffx]-(vis[ffy]==1)*(dp1[ffy]+a[ffy]-2ll*E[ffy])+(ds1[x]+ds1[y]-ds1[lca]-ds1[fa[lca][0]])-(ds2[x]+ds2[y]-2ll*ds2[lca]);} } int main() {scanf("%d%d",&n,&q);for(int i=1;i<=n;i++)scanf("%lld",&a[i]);ll v;for(int f,t,i=1;i<n;i++){scanf("%d%d%lld",&f,&t,&v);ae(f,t,v),ae(t,f,v);}ds1[1]=a[1];dfs1(1,1);for(int k=1;k<=20;k++)for(int i=1;i<=n;i++)fa[i][k]=fa[fa[i][k-1]][k-1];dfs(1);Dfs(1);for(int x,y,i=1;i<=q;i++){scanf("%d%d",&x,&y);printf("%lld\n",sol(x,y));}return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/LiGuanlin1124/p/9887204.html
總結(jié)
以上是生活随笔為你收集整理的CF1000G Two-Paths的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: react native使用百度echa
- 下一篇: 牛客ACM赛 B [小a的旅行计划 ]