树剖||树链剖分||线段树||BZOJ4034||Luogu3178||[HAOI2015]树上操作
好像其他人都嫌这道题太容易了懒得讲,好吧那我讲。
题解:第一个操作和第二个操作本质上是一样的,所以可以合并。唯一值得讲的点就是:第二个操作要求把某个节点 x 为根的子树中所有点的点权都增加 a,我们可以发现一个子树中的结点在线段树中会是连续的一段,而这段数最后一个就是seg值(seg数组在Dfs2中有进行预处理,seg[x]:x结点在线段树中的位置)最大的那个。所以可以在Dfs2中多预处理一个tu[x]表示以x为根的子树中seg值最大的结点的seg值。接下来进行操作二时Update(1,seg[x],tu[x])就可以了。总体挺模版的,而且由于询问只询问x到根的和,所以不需要预处理dep数组。记得开ll。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define ll long long 5 #define max(a,b) ((a)>(b)?(a):(b)) 6 using namespace std; 7 inline ll rd(){ 8 ll x=0,f=1;char c=getchar(); 9 while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} 10 while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} 11 return f*x; 12 } 13 const ll maxn=100005,maxq=100005; 14 ll N,Q,num_edge=0,edge_head[maxn],W[maxn],a,b,seg[maxn],rev[maxn],fa[maxn]; 15 ll top[maxn],son[maxn],size[maxn],tu[maxn],X,A,Ans,o; 16 struct Edge{ 17 int to,nx; 18 }edge[maxn<<1]; 19 inline void Add_edge(int from,int to){ 20 edge[++num_edge].nx=edge_head[from]; 21 edge[num_edge].to=to; 22 edge_head[from]=num_edge; 23 return; 24 } 25 inline void Dfs1(int x,int f){ 26 fa[x]=f; 27 size[x]=1; 28 for(int i=edge_head[x];i;i=edge[i].nx){ 29 int y=edge[i].to; 30 if(y!=f){ 31 Dfs1(y,x); 32 size[x]+=size[y]; 33 if(size[y]>size[son[x]])son[x]=y; 34 } 35 } 36 return; 37 } 38 inline void Dfs2(int x){ 39 tu[x]=seg[0]; 40 if(son[x]){ 41 int y=son[x]; 42 seg[y]=++seg[0];//seg[x]:x在线段树中的下标 43 rev[seg[0]]=y; 44 top[y]=top[x]; 45 Dfs2(y); 46 tu[x]=max(tu[x],tu[y]); 47 } 48 for(int i=edge_head[x];i;i=edge[i].nx){ 49 int y=edge[i].to; 50 if(top[y]==0){ 51 seg[y]=++seg[0]; 52 rev[seg[0]]=y; 53 top[y]=y; 54 Dfs2(y); 55 tu[x]=max(tu[x],tu[y]); 56 } 57 } 58 return; 59 } 60 struct Tree{ 61 ll sum,l,r,flag; 62 }t[maxn<<3]; 63 inline void Build(int k,int l,int r){ 64 t[k].l=l;t[k].r=r; 65 if(l==r){ 66 t[k].sum=W[rev[l]]; 67 return; 68 } 69 int mid=(l+r)>>1,ls=k<<1,rs=k<<1|1; 70 Build(ls,l,mid);Build(rs,mid+1,r); 71 t[k].sum=t[ls].sum+t[rs].sum; 72 return; 73 } 74 inline void Pushdown(int k){ 75 if(t[k].flag){ 76 int ls=k<<1,rs=k<<1|1,ln=t[ls].r-t[ls].l+1,rn=t[rs].r-t[rs].l+1; 77 t[ls].sum+=t[k].flag*ln;t[rs].sum+=t[k].flag*rn; 78 t[ls].flag+=t[k].flag;t[rs].flag+=t[k].flag; 79 t[k].flag=0; 80 } 81 return; 82 } 83 inline void Update(int k,int ql,int qr,ll s){ 84 int l=t[k].l,r=t[k].r; 85 if(ql<=l&&r<=qr){ 86 t[k].sum+=s*(r-l+1); 87 t[k].flag+=s; 88 return; 89 } 90 Pushdown(k); 91 int mid=(l+r)>>1,ls=k<<1,rs=k<<1|1; 92 if(ql<=mid)Update(ls,ql,qr,s); 93 if(qr>mid)Update(rs,ql,qr,s); 94 t[k].sum=t[ls].sum+t[rs].sum; 95 return; 96 } 97 inline void Query(int k,int ql,int qr){ 98 int l=t[k].l,r=t[k].r; 99 if(ql<=l&&r<=qr){ 100 Ans+=t[k].sum; 101 return; 102 } 103 Pushdown(k); 104 int mid=(l+r)>>1,ls=k<<1,rs=k<<1|1; 105 if(ql<=mid)Query(ls,ql,qr); 106 if(qr>mid)Query(rs,ql,qr); 107 return; 108 } 109 inline ll Ask(int x){ 110 int fx=top[x]; 111 Ans=0; 112 while(fx!=1){ 113 Query(1,seg[fx],seg[x]); 114 x=fa[fx]; 115 fx=top[x]; 116 } 117 Query(1,1,seg[x]); 118 return Ans; 119 } 120 int main(){ 121 N=rd();Q=rd(); 122 for(int i=1;i<=N;i++)W[i]=rd(); 123 for(int i=1;i<N;i++){ 124 a=rd();b=rd(); 125 Add_edge(a,b); 126 Add_edge(b,a); 127 } 128 Dfs1(1,0); 129 seg[0]=seg[1]=rev[1]=top[1]=1; 130 Dfs2(1); 131 Build(1,1,N); 132 while(Q--){ 133 o=rd(); 134 if(o==1||o==2){ 135 X=rd();A=rd(); 136 if(o==1)Update(1,seg[X],seg[X],A); 137 else Update(1,seg[X],tu[X],A); 138 } 139 else{ 140 X=rd(); 141 printf("%lld\n",Ask(X)); 142 } 143 } 144 return 0; 145 }
By:AlenaNuna