HDU 3966(树链剖分)
生活随笔
收集整理的這篇文章主要介紹了
HDU 3966(树链剖分)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
傳送門
題意:
給你一個(gè)有nnn個(gè)頂點(diǎn)的樹,樹上的每一個(gè)點(diǎn)都有一個(gè)點(diǎn)權(quán),現(xiàn)在有333種操作:
- IuvkI~ u~v~kI?u?v?k,代表將結(jié)點(diǎn)uuu到結(jié)點(diǎn)vvv的最近的路徑上的所有點(diǎn)的點(diǎn)權(quán)增加kkk
- DuvkD~ u~v~kD?u?v?k ,代表將結(jié)點(diǎn)uuu到結(jié)點(diǎn)vvv的最近的路徑上的所有點(diǎn)的點(diǎn)權(quán)減少kkk
- QuQ~ uQ?u,代表求出結(jié)點(diǎn)uuu的點(diǎn)權(quán)。
題目分析:
樹鏈剖分的模板題。
倘若只有操作111和操作222,則我們只需要用樹上差分用O(n+m)\mathcal{O}(n+m)O(n+m)的時(shí)間復(fù)雜度完成操作。
但是,現(xiàn)在這個(gè)問題中,因此操作333的存在,使得用樹上差分去做的話時(shí)間復(fù)雜度將會不優(yōu)。
因此我們可以考慮采用樹鏈剖分。
我們將樹上的重鏈剖分出來之后,獲取出他們的dfsdfsdfs序,并用數(shù)據(jù)結(jié)構(gòu)(線段樹/樹狀數(shù)組)去維護(hù)區(qū)間的和即可。
代碼:
#include <bits/stdc++.h> using namespace std; const int maxn=50005; struct Node{int to,next; }q[100005]; struct ST{int sum,len,lazy; }tr[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){q[cnt].to=to;q[cnt].next=head[from];head[from]=cnt++; } void dfs1(int x){size[x]=1,dis[x]=dis[f[x]]+1;for(int i=head[x];i!=-1;i=q[i].next){int to=q[i].to;if(to==f[x]) continue;f[to]=x;dfs1(to);size[x]+=size[to];if(size[to]>size[son[x]]){son[x]=to;}} } void dfs2(int x,int t){top[x]=t;id[x]=++tot;rk[tot]=x;if(son[x]) dfs2(son[x],t);for(int i=head[x];i!=-1;i=q[i].next){int to=q[i].to;if(to==son[x]||to==f[x]) continue;dfs2(to,to);} } void push_up(int rt){tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum; } void push_down(int rt){if(tr[rt].lazy){tr[rt<<1].sum+=1ll*tr[rt].lazy*tr[rt<<1].len;tr[rt<<1|1].sum+=1ll*tr[rt].lazy*tr[rt<<1|1].len;tr[rt<<1].lazy=tr[rt<<1].lazy+tr[rt].lazy;tr[rt<<1|1].lazy=tr[rt<<1|1].lazy+tr[rt].lazy;tr[rt].lazy=0;} } void build(int l,int r,int rt){tr[rt].lazy=0;tr[rt].len=r-l+1;if(l==r){tr[rt].sum=v[rk[l]];return ;}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){if(L<=l&&R>=r){tr[rt].lazy=tr[rt].lazy+k;tr[rt].sum=tr[rt].sum+tr[rt].len*k*1l;return ;}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); } int query(int L,int R,int l,int r,int rt){if(L<=l&&R>=r){return tr[rt].sum;}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){int res=0;while(top[x]!=top[y]){if(dis[top[x]]<dis[top[y]]) swap(x,y);res+=query(id[top[x]],id[x],1,tot,1);x=f[top[x]];}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){while(top[x]!=top[y]){if(dis[top[x]]<dis[top[y]]) swap(x,y);update(id[top[x]],id[x],1,tot,1,c);x=f[top[x]];}if(id[x]>id[y]) swap(x,y);update(id[x],id[y],1,tot,1,c); } int main() {int n,m,t;while(~scanf("%d%d%d",&n,&m,&t)){memset(head,-1,sizeof(head));memset(dis,0,sizeof(dis));memset(son,0,sizeof(son));tot=0;cnt=0;for(int i=1;i<=n;i++) scanf("%d",&v[i]);for(int i=1;i<n;i++){int from,to;scanf("%d%d",&from,&to);add_edge(from,to);add_edge(to,from);}dfs1(1);dfs2(1,1);build(1,tot,1);while(t--){int x,y,z;char op[2];scanf("%s",op);if(op[0]=='I'){scanf("%d%d%d",&x,&y,&z);UPDATE(x,y,z);}if(op[0]=='D'){scanf("%d%d%d",&x,&y,&z);z=-z;UPDATE(x,y,z);}if(op[0]=='Q'){scanf("%d",&x);int res=query(id[x],id[x],1,tot,1);printf("%d\n",res);}}}return 0; }總結(jié)
以上是生活随笔為你收集整理的HDU 3966(树链剖分)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Flask-SQLAlchemy的使用(
- 下一篇: 3.2 电信数据清洗