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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

codeforces E. Jamie and Tree LCA+dfs序+线段树

發布時間:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 codeforces E. Jamie and Tree LCA+dfs序+线段树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題解:

寫起來還稍微有點麻煩。
dfs序+線段樹可以維護子樹的整體修改和查詢。 因此,這道題我們要往子樹上靠。
我們首先從1號點進行dfs遍歷,順便求出點的dfs序和深度,然后我們采用倍增的思想,可以預處理出每個點的祖先是誰。然后可以在O(log(n))O(log(n))的時間復雜度內求出任意兩點的lca(u,v)lca(u,v)
而現在整個樹的根是可以改變的,因此,我們需要一個結論,也就是說當樹的根節點被改變為root時候,u和v的新的lca,也就是newlca(u,v)=lca(u,v)xorlca(u,root)xorlca(v,root)newlca(u,v)=lca(u,v)xorlca(u,root)xorlca(v,root) (這個可以自己畫畫圖看一下)。
找到newlca以后還不行,根據newlca與root的關系不一樣,還需要進一步討論。
1. 當newlca=rootnewlca=root的時候,要操作的子樹就是整顆樹。
2. 當lca(newlca,root)!=newlcalca(newlca,root)!=newlca 那么要操作的子樹就是以1為根節點時候的newlca的子樹。
3. 當lca(newlca,root)==newlcalca(newlca,root)==newlca的時候,那么要操作的就是整顆樹減去以(root到newlca鏈上深度為dep[newlca]-1的)點的子樹。

#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define int long long #define pr(x) cout<<#x<<":"<<x<<endl const int maxn = 1e5+7; int n,q; struct edge{int u,v,nxt; }es[maxn<<1]; int head[maxn]; int tot = 0; void addedge(int u,int v){es[tot].u = u,es[tot].v = v,es[tot].nxt = head[u];head[u] = tot++; } int fa[maxn][22],dep[maxn]; int idx = 0,IN[maxn],OUT[maxn]; int segtree[maxn<<3],addmark[maxn<<3]; void init(){memset(fa,0,sizeof(fa));memset(head,-1,sizeof(head));memset(IN,0,sizeof(IN));memset(OUT,0,sizeof(OUT));memset(dep,0,sizeof(dep));tot = idx = 0; } void dfs(int u,int myfa,int dp){dep[u] = dp;IN[u] = ++idx;for(int e = head[u];e != -1;e = es[e].nxt){int v = es[e].v;if(v == myfa) continue;fa[v][0] = u;dfs(v,u,dp+1);}OUT[u] = ++idx; } void pushdown(int rt,int lft,int rgt){if(addmark[rt]){int mid = (lft + rgt)/2;addmark[2*rt] += addmark[rt];addmark[2*rt+1] += addmark[rt];segtree[2*rt] += addmark[rt]*(mid-lft+1);segtree[2*rt+1] += addmark[rt]*(rgt-mid);addmark[rt] = 0;} } void pushup(int rt){segtree[rt] = segtree[rt*2] + segtree[rt*2+1]; } int val[maxn]; /* void build(int rt,int L,int R){if(R == L) {segtree[rt] = val[L];}else{build(L,mid);build(mid+1,R);} }*/ void ins(int rt,int lft,int rgt,int L,int R,int adv){if(rgt < L || lft > R) return ;if(L <= lft && R >= rgt) {segtree[rt] += (rgt-lft+1)*adv;addmark[rt] += adv;return ;}int mid = (lft + rgt) / 2;pushdown(rt,lft,rgt);ins(rt*2,lft,mid,L,R,adv);ins(rt*2+1,mid+1,rgt,L,R,adv);pushup(rt); } int ask(int rt,int lft,int rgt,int L,int R){if(rgt < L || lft > R) return 0;if(L <= lft && R >= rgt) return segtree[rt];pushdown(rt,lft,rgt);int mid = (lft + rgt)/2;return ask(rt*2,lft,mid,L,R) + ask(rt*2+1,mid+1,rgt,L,R); } void makelca(){for(int i = 1;i < 20;++i){for(int u = 1;u <= n;++u){fa[u][i] = fa[fa[u][i-1]][i-1];}} } int lca(int u,int v){if(dep[u] < dep[v]) swap(u,v);int dpc = dep[u] - dep[v];if(dpc){int t = 0;while(dpc){if(dpc & 1)u = fa[u][t];t++;dpc >>= 1;}}if(u == v) return u;for(int i = 19;u != v && i >= 0;--i ){if(fa[u][i] != fa[v][i]) {u = fa[u][i];v = fa[v][i];}}return fa[u][0]; }int root = 1; main(){init();scanf("%lld%lld",&n,&q);for(int i = 1;i <= n;++i){scanf("%lld",&val[i]);}for(int i = 0;i < n-1;++i){int u,v;scanf("%lld%lld",&u,&v);addedge(u,v);addedge(v,u);}dfs(1,-1,0);makelca();for(int i = 1;i <= n;++i){ins(1,1,2*n,IN[i],IN[i],val[i]);ins(1,1,2*n,OUT[i],OUT[i],val[i]);}//計算lcafor(int i = 0;i < q;++i){int op ;scanf("%lld",&op);if(op == 1){scanf("%lld",&root);}else if(op == 2){int u,v,x;scanf("%lld%lld%lld",&u,&v,&x);int rt = lca(u,v)^lca(u,root)^lca(root,v);if(rt == root) ins(1,1,2*n,1,2*n,x);else if(lca(rt,root) != rt) ins(1,1,2*n,IN[rt],OUT[rt],x);else{int dpc = dep[root]-dep[rt]-1;int t = 0;int tmp = root;while(dpc){if(dpc&1)tmp = fa[tmp][t];t++;dpc >>= 1;}//cout<<tmp<<' '<<IN[tmp]<<' '<<OUT[tmp]<<endl;ins(1,1,2*n,1,2*n,x);ins(1,1,2*n,IN[tmp],OUT[tmp],-x);}}else if(op == 3){int v;scanf("%lld",&v);if(v == root){printf("%lld\n",ask(1,1,2*n,1,2*n)/2);}else if(lca(v,root) != v){printf("%lld\n",ask(1,1,2*n,IN[v],OUT[v])/2);}else{int tmp = root;int dpc = dep[root]-1-dep[v];int t = 0;while(dpc){if(dpc&1)tmp = fa[tmp][t];++t;dpc >>= 1;}int ans = (ask(1,1,2*n,1,2*n)-ask(1,1,2*n,IN[tmp],OUT[tmp]))/2;printf("%lld\n",ans);}}}//return 0; }

總結

以上是生活随笔為你收集整理的codeforces E. Jamie and Tree LCA+dfs序+线段树的全部內容,希望文章能夠幫你解決所遇到的問題。

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