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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

山东理工大学第十二届ACM程序设计竞赛 - Cut the tree(树上启发式合并+线段树)

發布時間:2024/4/11 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 山东理工大学第十二届ACM程序设计竞赛 - Cut the tree(树上启发式合并+线段树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題目大意:給一個具有 N 個節點的有根樹,以 1 號節點為根,節點編號從 1 開始,點有點權。樹的第 H 層權值為深度為 H 的所有點的點權之和。樹的總權值為所有層權值的最大值。問分別割掉以 1,2,..,N 為根的子樹后,剩余樹的總權值為多少。

題目分析:因為題目提示了,弱化數據后支持雙 log 的算法。。所以不難想到樹上啟發式合并+線段樹,兩個模板套起來就過了,線段樹負責處理區間最大值問題,每次更新子樹信息的時候,單點更新一下相關層的最大值就好了,記得回溯

代碼:
?

#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> using namespace std;typedef long long LL;typedef unsigned long long ull;const LL inf=0x3f3f3f3f;const int N=1e5+100;LL a[N],sum[N],ans[N];struct Node {int l,r;LL mmax; }tree[N<<2];void pushup(int k) {tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax); }void build(int k,int l,int r) {tree[k].l=l;tree[k].r=r;if(l==r){tree[k].mmax=sum[l];return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k); }void update(int k,int pos,int val) {if(tree[k].l==tree[k].r){tree[k].mmax+=val;return;}int mid=tree[k].l+tree[k].r>>1;if(pos<=mid)update(k<<1,pos,val);elseupdate(k<<1|1,pos,val);pushup(k); }int num[N],son[N],deep[N],max_deep;bool vis[N];vector<int>node[N];void dfs_son(int u,int fa,int dep)//樹鏈剖分跑出重鏈 {max_deep=max(max_deep,dep);sum[dep]+=a[u];deep[u]=dep;son[u]=-1;num[u]=1;for(auto v:node[u]){if(v==fa)continue;dfs_son(v,u,dep+1);num[u]+=num[v];if(son[u]==-1||num[v]>num[son[u]])son[u]=v;} }void cal(int u,int fa,int val)//對于每個節點計算其子樹的貢獻 {update(1,deep[u],val*a[u]);for(auto v:node[u]){if(v==fa||vis[v])continue;cal(v,u,val);} }void dfs(int u,int fa,int keep)//啟發式合并 {for(auto v:node[u]){if(v==fa||v==son[u])continue;dfs(v,u,0);}if(son[u]!=-1){dfs(son[u],u,1);vis[son[u]]=true;}cal(u,fa,-1);ans[u]=tree[1].mmax;if(son[u]!=-1)vis[son[u]]=false;if(!keep)cal(u,fa,1); }int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n;scanf("%d",&n);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);node[u].push_back(v);node[v].push_back(u);}for(int i=1;i<=n;i++)scanf("%lld",a+i);dfs_son(1,-1,1);build(1,1,max_deep);dfs(1,-1,1);printf("%lld",ans[1]);for(int i=2;i<=n;i++)printf(" %lld",ans[i]);puts("");return 0; }

?

總結

以上是生活随笔為你收集整理的山东理工大学第十二届ACM程序设计竞赛 - Cut the tree(树上启发式合并+线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。

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