1. 程式人生 > >bzoj4034 樹上操作 樹鏈剖分+線段樹

bzoj4034 樹上操作 樹鏈剖分+線段樹

題目傳送門

題目大意:

有一棵點數為 N 的樹,以點 1 為根,且樹點有權。然後有 M 個操作,分為三種: 操作 1 :把某個節點 x 的點權增加 a 。 操作 2 :把某個節點 x 為根的子樹中所有點的點權都增加 a 。 操作 3 :詢問某個節點 x 到根的路徑中所有點的點權和。   思路:   由於是在刷dfs序專題的時候碰到這題,所以思路被限制了,沒想樹鏈剖分的東西,沒能做出來,後來發現了一個  大佬的部落格,發現也是可以做的,但是這個做法看不懂。。。留坑   現在用樹鏈剖分的方法,每個點的權值就是點本身的權值,對於1和2兩種操作,直接使用線段樹修改就可以了,無非是單點和區間的區別,這裡推薦用線段樹版本的樹鏈剖分,雖然線段樹比樹狀陣列長很多,但是不需要考慮一些邊界值加加減減的問題,比賽的時候想那個很可能犯錯,用線段樹來修改就簡單多了(大佬無視這句話)。   而對於查詢操作,用的也是樹鏈剖分往上跳的方法,每次都跳到重鏈,然後把這段區間的值加起來,(由於是重鏈,所以dfs序是連續的),這樣就可以通過log(n)的時間得到鏈的權重了。   所以除了這一點就是個樹鏈剖分的模板題了,線段樹直接網上找了一個板子,一發A,做題還是太少。
#include<cstdio>
#include
<algorithm> //#include<iostream> #include<vector> #include<map> #include<set> #include<cstring> #include<queue> #include<stack> #include<stdlib.h> //#include<unordered_map> #define lson (o<<1) #define rson ((o<<1)|1) #define CLR(a,b) memset(a,b,sizeof(a)) #define
mkp(a,b) make_pair(a,b) typedef long long ll; using namespace std; const int maxn=100010; vector<int> edge[maxn]; int n,m,op,x,tot,val[maxn],l[maxn],r[maxn],deep[maxn],son[maxn],fa[maxn],top[maxn],fin[maxn]; ll sum[maxn<<3],lazy[maxn<<3],size[maxn<<3]; inline void dfs_1(int x,int
pre) { fa[x] = pre; son[x] = -1; size[x] = 1; deep[x] = deep[pre]+1; for(int i = 0; i < edge[x].size(); i++) if(edge[x][i] != pre) { dfs_1(edge[x][i],x); size[x] += size[edge[x][i]]; if(son[x]==-1 || size[edge[x][i]]>size[son[x]]) son[x] = edge[x][i]; } } inline void dfs_2(int x,int root) { top[x] = root; l[x] = ++tot; fin[l[x]] = x; if(son[x] != -1) dfs_2(son[x],root); for(int i = 0; i < edge[x].size(); i++) if(edge[x][i] != fa[x] && edge[x][i] != son[x]) dfs_2(edge[x][i],edge[x][i]); r[x]=tot; } inline void maintain(int o,int l,int r) { if(l!=r)sum[o]=sum[lson]+sum[rson]; } inline void pushdown(int o,int l,int r) { if(lazy[o]) { sum[lson]+=size[lson]*lazy[o]; sum[rson]+=size[rson]*lazy[o]; lazy[lson]+=lazy[o]; lazy[rson]+=lazy[o]; } lazy[o]=0; } inline void build(int o,int l,int r) { if(l==r) { sum[o]=(ll)val[fin[l]]; size[o]=1; return; } int mid = (l+r)/2; build(lson,l,mid); build(rson,mid+1,r); maintain(o,l,r); size[o]=size[lson]+size[rson]; } inline void update(int o,int l,int r,int L,int R,int v) { pushdown(o,l,r); if(R<l || L>r)return; if(l>=L && r<=R) { lazy[o]+=(ll)v; sum[o]+=((ll)size[o])*((ll)v); return; } int mid=(l+r)>>1; update(lson,l,mid,L,R,v); update(rson,mid+1,r,L,R,v); maintain(o,l,r); } inline ll query(int o,int l,int r,int L,int R) { pushdown(o,l,r); if(R<l || L>r)return 0; if(l>=L && r<=R)return sum[o]; int mid=(l+r)>>1; return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R); } inline ll get(int x) { ll ret = 0; while(top[x]!=1) { ret+=query(1,1,n,l[top[x]],l[x]); x=fa[top[x]]; } ret+=query(1,1,n,1,l[x]); return ret; } int main() { scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&val[i]),sum[i]=i; int u,v; for(int i = 1; i < n; i++) { scanf("%d%d",&u,&v); edge[u].push_back(v); edge[v].push_back(u); } dfs_1(1,0); dfs_2(1,1); build(1,1,n); for(int i = 0; i < m; i++) { scanf("%d%d",&op,&x); if(op==1) { scanf("%d",&v); update(1,1,n,l[x],l[x],v); } if(op==2) { scanf("%d",&v); update(1,1,n,l[x],r[x],v); } if(op==3)printf("%lld\n",get(x)); } return 0; }