給你乙個有n
nn個頂點的樹,樹上的每乙個點都有乙個點權,現在有3
33種操作:
樹鏈剖分的模板題。
倘若只有操作1
11和操作2
22,則我們只需要用樹上差分用o(n
+m
)\mathcal(n+m)
o(n+m)
的時間複雜度完成操作。
但是,現在這個問題中,因此操作3
33的存在,使得用樹上差分去做的話時間複雜度將會不優。
因此我們可以考慮採用樹鏈剖分。
我們將樹上的重鏈剖分出來之後,獲取出他們的dfs
dfsdf
s序,並用資料結構(線段樹/樹狀陣列)去維護區間的和即可。
#include
using
namespace std;
const
int maxn=
50005
;struct nodeq[
100005];
struct sttr[maxn<<2]
;int head[maxn]
,cnt=
0,tot=
0,f[maxn]
,dis[maxn]
,son[maxn]
,size[maxn]
,top[maxn]
;int id[maxn]
,rk[maxn]
,v[maxn]
;void
add_edge
(int from,
int to)
void
dfs1
(int x)}}
void
dfs2
(int x,
int t)
}void
push_up
(int rt)
void
push_down
(int rt)
}void
build
(int l,
int r,
int rt)
int mid=
(l+r)
>>1;
build
(l,mid,rt<<1)
;build
(mid+
1,r,rt<<1|
1);push_up
(rt);}
void
update
(int l,
int r,
int l,
int r,
int rt,
int k)
push_down
(rt)
;int mid=
(l+r)
>>1;
if(l<=mid)
update
(l,r,l,mid,rt<<
1,k);if
(r>mid)
update
(l,r,mid+
1,r,rt<<1|
1,k)
;push_up
(rt);}
intquery
(int l,
int r,
int l,
int r,
int rt)
push_down
(rt)
;int mid=
(l+r)
>>1;
int res=0;
if(l<=mid) res+
=query
(l,r,l,mid,rt<<1)
;if(r>mid) res+
=query
(l,r,mid+
1,r,rt<<1|
1);return res;
}int
cal(
int x,
int y)
if(id[x]
>id[y]
)swap
(x,y)
; res+
=query
(id[x]
,id[y],1
,tot,1)
;return res;
}void
update
(int x,
int y,
int c)
if(id[x]
>id[y]
)swap
(x,y)
;update
(id[x]
,id[y],1
,tot,
1,c);}
intmain()
dfs1(1
);dfs2(1
,1);
build(1
,tot,1)
;while
(t--)if
(op[0]
=='d')if
(op[0]
=='q')}
}return0;
}
HDU3966 樹鏈剖分
題目 aragorn s story 題意 給一棵樹,並給定各個點權的值,然後有3種操作 i c1 c2 k 把c1與c2的路徑上的所有點權值加上k d c1 c2 k 把c1與c2的路徑上的所有點權值減去k q c 查詢節點編號為c的權值 分析 典型的樹鏈剖分題目,先進行剖分,然後用線段樹去維護即...
hdu3966 樹鏈剖分
近期在強化知識點深度。發現樹鏈剖分不是非常會寫了。回想一下改動操作 若兩個點在同一條鏈上,則直接改動這段區間。若不在同一條鏈上,改動深度較大的點到其鏈頂端的區間,同一時候將這個點變為他所在鏈頂端的父親,迴圈操作直到這兩個點在同一條鏈上。就能夠用上一種方法了。沒實用lca寫是由於曾經被坑過,不但沒有這...
HDU3966 樹鏈剖分
題目 aragorn s story 題意 給一棵樹,並給定各個點權的值,然後有3種操作 i c1 c2 k 把c1與c2的路徑上的所有點權值加上k d c1 c2 k 把c1與c2的路徑上的所有點權值減去k q c 查詢節點編號為c的權值 分析 典型的樹鏈剖分題目,先進行剖分,然後用線段樹去維護即...