日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CF1000G Two-Paths

發布時間:2024/9/5 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CF1000G Two-Paths 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目大意:給你一棵樹,其中點上和邊上都有值。定義2-Path為經過一條邊最多兩次的路徑,價值為經過點的權值加和-經過邊權值*該邊經過次數。4e5組詢問,每次詢問樹上連接x,y兩點的2-Path的最大價值。

先說一句:

機房中認為圖畫的最好:https://blog.csdn.net/lleozhang/article/details/83659914

題解:

一道狀態比較多的樹形dp。

dp1:記錄x點子樹內從x到x的最大2-Path的價值-x的值。

dp2:記錄從fa[x]到fa[x]不經過x且不經過fa[fa[x]]的最大2-Path價值-fa[x]的值。

dp3:記錄從fa[x]到fa[x]不經過x的任意兒子的2-Path的價值-x的值。

(描述比較惡心,見圖)

(圖也比較惡心)

紅色的邊和涂黑的未知物體都要取。

然后還有比較大眾的ds1:記錄x到根的點權之和,和ds2:記錄x到根的邊權之和。

還要求一下每個點到根節點經過點的dp2之和。

dfsO(n)搞dp,詢問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; }

?

轉載于:https://www.cnblogs.com/LiGuanlin1124/p/9887204.html

總結

以上是生活随笔為你收集整理的CF1000G Two-Paths的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。