1. 程式人生 > >BZOJ4034 [HAOI2015]T2 題解&程式碼

BZOJ4034 [HAOI2015]T2 題解&程式碼

題意: 有一棵有N個節點的樹,以節點1為根,且點上有權。
有M個操作,分為三種:
操作 1 把節點x的點權增加 a
操作 2 把以節點x為根的樹中所有點的點權都增加a
操作 3 求節點x到根的路徑中所有點的點權和

分析:
操作1和操作2本質上是沒有區別的,區間修改和單點修改顯然可以合併,求dfs序後線段樹區間維護就可以了
操作3是涉及路徑的查詢,和樹剖很類似,但是比樹剖簡單很多【比如我求的deep完全沒有用2333333】,按照樹剖的思路分段查詢即可

note:
線段樹八倍空間!不然會迷之RE!明明四倍理論上是可以的QAQ
最開始初始化忘記初始化size[]了…於是各種算錯233333我個智障

/**************************************************************
    Problem: 4034
    User: Rainbow6174
    Language: C++
    Result: Accepted
    Time:3920 ms
    Memory:29872 kb
****************************************************************/

#include<iostream>
#include<vector>
#include<cstdio>
#define lson (o<<1) #define rson ((o<<1)|1) #define LL long long using namespace std; const int maxn = 100005; vector<int> edge[maxn]; int n,m,op,x,tot,val[maxn],in[maxn],out[maxn],deep[maxn],son[maxn],fa[maxn],rt[maxn],fin[maxn]; LL sum[8*maxn],lazy[8*maxn],size[8*maxn]; void dfs1(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) { dfs1(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]; } } void dfs2(int x,int root) { rt[x] = root; in[x] = out[x] = ++tot; fin[in[x]] = x; if(son[x] != -1)dfs2(son[x],root); for(int i = 0; i < edge[x].size(); i++) if(edge[x][i] != fa[x] && edge[x][i] != son[x]) dfs2(edge[x][i],edge[x][i]); out[x]=tot; } void maintain(int o,int l,int r) { if(l!=r)sum[o]=sum[lson]+sum[rson]; } 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; } void build(int o,int l,int r) { if(l==r) { sum[o]=(LL)val[fin[l]]; size[o]=1; //cout<<o<<' '<<sum[o]<<endl; 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]; } void addtree(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); //cout<<"test "<<o<<' '<<l<<' '<<r<<' '<<sum[o]<<endl; return; } int mid=(l+r)>>1; addtree(lson,l,mid,L,R,v); addtree(rson,mid+1,r,L,R,v); maintain(o,l,r); } 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); } LL Query(int x) { LL ret = 0; while(rt[x]!=1) { ret+=query(1,1,n,in[rt[x]],in[x]); x=fa[rt[x]]; } ret+=query(1,1,n,1,in[x]); return ret; } int main(void) { 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); } dfs1(1,0);dfs2(1,1); build(1,1,n); for(int i = 0; i < m; i++) { scanf("%d%d",&op,&x); if(op==1) { scanf("%d",&v); addtree(1,1,n,in[x],in[x],v); } if(op==2) { scanf("%d",&v); addtree(1,1,n,in[x],out[x],v); } if(op==3)printf("%lld\n",Query(x)); } return 0; }