P3979 遙遠的國度(換根樹剖)
肯定不可能對每次換根重新樹剖一次
那就是隻以根 1 1 1剖一次來換根
其中 r o o t root root表示當前的根, u u u表示詢問 u u u子樹內的最小值
分情況討論
Ⅰ . 若 u = = r o o t Ⅰ.若u==root Ⅰ.若u==root,明顯所輸出 a [ 1 ] a[1] a[1],全域性最小值
Ⅱ . 若 u 的 深 度 大 於 r o o t 且 u 在 1 到 r o o t 的 鏈 上 , 那 麼 開 始 換 根 Ⅱ.若u的深度大於root且u在1到root的鏈上,那麼開始換根 Ⅱ.若u的深度大於root且u在1到root的鏈上,那麼開始換根
此 時 我 們 找 到 在 r o o t 到 u 的 鏈 上 的 v 是 u 的 直 系 兒 子 此時我們找到在root到u的鏈上的v是u的直系兒子 此時我們找到在root到u的鏈上的v是u的直系兒子
除 掉 以 v 為 根 子 樹 的 影 響 就 是 答 案 ( 由 於 子 樹 編 號 連 續 , 所 以 很 好 求 ) 除掉以v為根子樹的影響就是答案(由於子樹編號連續,所以很好求) 除掉以v為根子樹的影響就是答案(由於子樹編號連續,所以很好求)
Ⅲ . 剩 下 的 情 況 , 相 當 於 換 根 沒 影 響 , 直 接 查 詢 Ⅲ.剩下的情況,相當於換根沒影響,直接查詢 Ⅲ.剩下的情況,相當於換根沒影響,直接查詢
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define lson ls,l,mid
#define rson rs,mid+1,r
#define int long long
const int inf=1e15;
struct edge{
int to,nxt;
}d[maxn]; int head[maxn],cnt=1,num,n;
void add(int u,int v){
d[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
int laz[maxn],w[maxn],ww[maxn],root=1;
int deep[maxn],fa[maxn][25],siz[maxn],son[maxn],id[maxn],top[maxn],a[maxn];
void dfs1(int u,int f)
{
deep[u]=deep[f]+1, siz[u]=1;
for(int i=1;i<=log2(n);i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to; if( v==f ) continue;
fa[v][0]=u;
dfs1(v,u);
siz[u]+=siz[v];
if( siz[son[u]]<siz[v] ) son[u]=v;
}
}
int getfa(int x,int k)
{
for(int i=log2(n);i>=0;i--)
if( k&(1<<i) ) x=fa[x][i];
return x;
}
void dfs2(int u,int topf)
{
top[u]=topf, id[u]=++num, ww[num]=w[u];
if( son[u] ) dfs2(son[u],topf);
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( v==son[u]||v==fa[u][0] ) continue;
dfs2(v,v);
}
}
void build(int rt,int l,int r)
{
if( l==r ){ a[rt]=ww[l]; return; }
build(lson); build(rson);
a[rt] = min( a[ls],a[rs] );
}
void push_down(int rt)
{
if( laz[rt]==0 ) return;
laz[ls]=laz[rt], laz[rs]=laz[rt];
a[ls]=laz[rt], a[rs]=laz[rt];
laz[rt]=0;
}
void insert(int rt,int l,int r,int L,int R,int val)
{
if( l>=L&&r<=R ){ laz[rt]=val; a[rt]=val; return; }
if( r<L||l>R ) return;
push_down(rt);
insert(lson,L,R,val); insert(rson,L,R,val);
a[rt] = min( a[ls],a[rs] );
}
int query(int rt,int l,int r,int L,int R)
{
if( l>=L&&r<=R ) return a[rt];
if( r<L||l>R ) return inf;
push_down(rt);
return min( query(lson,L,R),query(rson,L,R) );
}
int lca(int l,int r)
{
while( top[l]!=top[r] )
{
if(deep[top[l]]<deep[top[r]]) swap(l,r);
l=fa[top[l]][0];
}
return deep[l]<deep[r]?l:r;
}
int find(int u)
{
int v;
if( u==root ) return a[1];//就是全域性最小值
if( deep[u]<deep[root]&&fa[v=getfa(root,deep[root]-deep[u]-1)][0]==u )//在鏈上
{
u=v;
int ans=query(1,1,n,1,id[u]-1);
ans = min( ans,query(1,1,n,id[u]+siz[u],n) );
return ans;
}
else
return query(1,1,n,id[u],id[u]+siz[u]-1);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int q; cin >> n >> q;
for(int i=1;i<n;i++)
{
int l,r; cin >> l >> r;
add(l,r); add(r,l);
}
for(int i=1;i<=n;i++) cin >> w[i];
dfs1(1,0); dfs2(1,1);
cin >> root;
build(1,1,n);
while( q-- )
{
int type,l,r,val;
cin >> type;
if( type == 1 ) cin >> root;
else if( type==2 )
{
cin >> l >> r >> val;
while( top[l]!=top[r] )
{
if( deep[top[l]]<deep[top[r]] ) swap(l,r);
insert(1,1,n,id[top[l]],id[l],val);
l=fa[top[l]][0];
}
if( deep[l]>deep[r] ) swap(l,r);
insert(1,1,n,id[l],id[r],val);
}
else
{
cin >> l;//求l子樹內的最小值
cout << find(l) << endl;
}
}
}
相關文章
- 遙遠的國度
- 樹鏈剖分
- 樹剖(不太會)
- [OI] 樹鏈剖分
- 2024.3.14 樹鏈剖分
- 樹鏈剖分解析
- 淺談樹鏈剖分
- 樹鏈剖分總結
- 樹剖 dsu on tree 長鏈
- Something about 樹鏈剖分
- 對樹鏈剖分的愛 題解
- 【筆記/模板】樹鏈剖分筆記
- #8. 「模板」樹鏈剖分
- 迴文樹線上剖分???
- [LOJ139]-樹鏈剖分
- 『dfn、樹剖雜項』Day9
- 「學習筆記」樹鏈剖分筆記
- 熟練剖分(tree) 樹形DP
- 樹鏈剖分學習筆記筆記
- P1505 [國家集訓隊]旅遊 (樹鏈剖分)
- P8025 【樹鏈剖分求祖先】
- bzoj4551: [Tjoi2016&Heoi2016]樹(樹鏈剖分)
- [ABC337G] Tree Inversion(換根 dp + 值域線段樹)
- bzoj3531: [Sdoi2014]旅行(樹鏈剖分+線段樹)
- 樹鏈剖分模板+入門題 SPOJ - QTREEQT
- 換根 DP
- 換根dp
- 一起來學習樹鏈剖分吧!
- BF的資料結構題單-提高組——樹鏈剖分資料結構
- 剖根問底:Java 不能實現真正泛型的原因是什麼?Java泛型
- TZOJ 8472 : Tree (重鏈剖分+線段樹) POJ 3237
- Echarts根據資料長度變換柱狀圖柱狀的顏色Echarts
- 空夜 [換根DP]
- 元宇宙產業化還很遙遠JEKV元宇宙產業
- 元宇宙產業化還很遙遠ZFF元宇宙產業
- 幾種不同資料採集的概念:遙測、遙控、遙信、遙調、遙視、遙感
- 情趣震動遙控智慧情趣解決方案/手機連線遠端遙控
- 域、域樹、域林、根域