树链剖分
#include<bits/stdc++.h> using namespace std; const int M=500500; struct TREE{int l,r,w,lz;}t[M<<2]; struct EDGE{int v,next;}e[M]; int head[M],edget,n,m,r,mod,w[M]; int deep[M],fa[M],son[M],siz[M]; //节点的深度 节点的父亲 节点的重儿子 节点子树的大小 int top[M],idn[M],cnt,val[M]; //节点所在重链的头节点 节点新的编号 新编号为i的点的点权 void add(int,int); //加边进入邻接表 int dfs1(int,int,int); //求每个节点的深度、重儿子和dfs序 void dfs2(int,int); //对整个树进行重新编号 void build(int,int,int); //建树 void update(int); //更新节点值 void IntervalAdd(int,int,int,int); //区间加 int IntervalSum(int,int,int); //区间求和 void down(int); //下推标记 void TreeSum(int,int); //求x到y路径上的和 void TreeAdd(int,int,int); //给x到y路径上的每一个点加val权值 int main(){ ios::sync_with_stdio(false); register int i; int x,y,z; char q; cin>>n>>m>>r>>mod; for(i=1;i<=n;++i) cin>>w[i]; for(i=1;i<n;++i){ cin>>x>>y; add(x,y); add(y,x); } dfs1(r,0,1); dfs2(r,r); build(1,n,1); for(i=1;i<=m;++i){ cin>>q; switch(q){ case '1':{cin>>x>>y>>z; TreeAdd(x,y,z); break;} case '2':{cin>>x>>y; TreeSum(x,y); break;} case '3':{cin>>x>>z; IntervalAdd(1,idn[x],idn[x]+siz[x]-1,z); break;} case '4':{cin>>x; printf("%d\n",IntervalSum(1,idn[x],idn[x]+siz[x]-1)%mod); break;} } } return 0; } void add(int x,int y){ e[++edget].v=y; e[edget].next=head[x]; head[x]=edget; } int dfs1(int x,int f,int dp){ fa[x]=f; deep[x]=dp; siz[x]=1; int maxsiz=-1; for(register int i=head[x];i;i=e[i].next){ if(e[i].v==f) continue; siz[x]+=dfs1(e[i].v,x,dp+1); if(siz[e[i].v]>maxsiz){ //修改重儿子 son[x]=e[i].v; maxsiz=siz[e[i].v]; } } return siz[x]; } void dfs2(int x,int topx){ //topx表示节点x所在重链的头节点 top[x]=topx; idn[x]=++cnt; val[cnt]=w[x]; if(!son[x]) return; dfs2(son[x],topx); for(register int i=head[x];i;i=e[i].next) if(!idn[e[i].v]) dfs2(e[i].v,e[i].v); } void build(int l,int r,int u){ t[u].l=l,t[u].r=r; if(l==r){ t[u].w=val[l]; return; } int m=(l+r)>>1; build(l,m,u<<1); build(m+1,r,u<<1|1); update(u); } void update(int u){ t[u].w=(t[u<<1].w+t[u<<1|1].w+mod)%mod; } void IntervalAdd(int u,int l,int r,int val){ if(t[u].l>=l && t[u].r<=r){ t[u].w+=(t[u].r-t[u].l+1)*val; t[u].lz+=val; return; } if(t[u].lz) down(u); int m=(t[u].l+t[u].r)>>1; if(m>=l) IntervalAdd(u<<1,l,r,val); if(m<r) IntervalAdd(u<<1|1,l,r,val); update(u); } int IntervalSum(int u,int l,int r){ int ans=0; if(t[u].l>=l && t[u].r<=r) return t[u].w; if(t[u].lz) down(u); int m=(t[u].l+t[u].r)>>1; if(m>=l) ans=(ans+IntervalSum(u<<1,l,r))%mod; if(m<r) ans=(ans+IntervalSum(u<<1|1,l,r))%mod; return ans; } void down(int u){ t[u<<1].lz+=t[u].lz; t[u<<1|1].lz+=t[u].lz; t[u<<1].w=(t[u<<1].w+(t[u<<1].r-t[u<<1].l+1)*t[u].lz)%mod; t[u<<1|1].w=(t[u<<1|1].w+(t[u<<1|1].r-t[u<<1|1].l+1)*t[u].lz)%mod; t[u].lz=0; } void TreeSum(int x,int y){ int ans=0; while(top[x]!=top[y]){ //当x和y不在同一重链上时,先跳到同一条重链上 if(deep[top[x]]<deep[top[y]]) swap(x,y); //把深度深的向上跳 ans=(ans+IntervalSum(1,idn[top[x]],idn[x]))%mod; //直接跳到fa[top[x]],并记录权值和 x=fa[top[x]]; } if(deep[x]>deep[y]) swap(x,y); //线段树的操作区间[l,r]要满足l<=r ans=(ans+IntervalSum(1,idn[x],idn[y]))%mod; printf("%d\n",ans); } void TreeAdd(int x,int y,int val){ while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); IntervalAdd(1,idn[top[x]],idn[x],val); x=fa[top[x]]; } if(deep[x]>deep[y]) swap(x,y); IntervalAdd(1,idn[x],idn[y],val); }
#include<bits/stdc++.h> using namespace std; const int M=500500; struct EDGE{int v,next;}e[M]; struct TREE{int l,r,w,maxn,lz;}t[M<<2]; int n,w[M],head[M],num,q,deep[M],cnt; int fa[M],top[M],idn[M],siz[M],son[M],val[M]; string s; inline void add(int,int); int dfs1(int,int,int); inline void dfs2(int,int); inline void build(int,int,int); inline void update(int); int IntervalSum(int,int,int); int IntervalMax(int,int,int); inline void SinglepointChange(int,int,int); inline void TreeSum(int,int); inline void TreeMax(int,int); int main(){ ios::sync_with_stdio(0); register int i,j; int x,y; cin>>n; for(i=1;i<n;++i){ cin>>x>>y; add(x,y); add(y,x); } for(i=1;i<=n;++i) cin>>w[i]; dfs1(1,0,1); dfs2(1,1); build(1,n,1); cin>>q; for(i=1;i<=q;++i){ cin>>s>>x>>y; if(s=="CHANGE") SinglepointChange(1,x,y); else if(s=="QMAX") TreeMax(x,y); else TreeSum(x,y); } return 0; } inline void add(int x,int y){ e[++num].v=y; e[num].next=head[x]; head[x]=num; } int dfs1(int x,int f,int dp){ fa[x]=f; deep[x]=dp; siz[x]=1; int maxsiz=-1; for(register int i=head[x];i;i=e[i].next){ if(e[i].v==f) continue; siz[x]+=dfs1(e[i].v,x,dp+1); if(siz[e[i].v]>maxsiz){ son[x]=e[i].v; maxsiz=siz[e[i].v]; } } return siz[x]; } inline void dfs2(int x,int topx){ idn[x]=++cnt; top[x]=topx; val[cnt]=w[x]; if(!son[x]) return; dfs2(son[x],topx); for(register int i=head[x];i;i=e[i].next) if(!idn[e[i].v]) dfs2(e[i].v,e[i].v); } inline void build(int l,int r,int u){ t[u].l=l,t[u].r=r; if(l==r){ t[u].w=t[u].maxn=val[l]; return; } int m=(l+r)>>1; build(l,m,u<<1); build(m+1,r,u<<1|1); update(u); } inline void update(int u){ t[u].w=t[u<<1].w+t[u<<1|1].w; t[u].maxn=max(t[u<<1].maxn,t[u<<1|1].maxn); } int IntervalSum(int u,int l,int r){ int sum=0; if(t[u].l>=l && t[u].r<=r) return t[u].w; int m=(t[u].l+t[u].r)>>1; if(m>=l) sum+=IntervalSum(u<<1,l,r); if(m<r) sum+=IntervalSum(u<<1|1,l,r); return sum; } int IntervalMax(int u,int l,int r){ int maxn=-1000000000; if(t[u].l>=l && t[u].r<=r) return t[u].maxn; int m=(t[u].l+t[u].r)>>1; if(m>=l) maxn=max(maxn,IntervalMax(u<<1,l,r)); if(m<r) maxn=max(maxn,IntervalMax(u<<1|1,l,r)); return maxn; } inline void SinglepointChange(int u,int x,int val){ if(t[u].l==idn[x] && t[u].r==idn[x]){ t[u].w=t[u].maxn=val; return; } int m=(t[u].l+t[u].r)>>1; if(m>=idn[x]) SinglepointChange(u<<1,x,val); if(m<idn[x]) SinglepointChange(u<<1|1,x,val); update(u); } inline void TreeSum(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); ans+=IntervalSum(1,idn[top[x]],idn[x]); x=fa[top[x]]; } if(deep[x]>deep[y]) swap(x,y); ans+=IntervalSum(1,idn[x],idn[y]); printf("%d\n",ans); } inline void TreeMax(int x,int y){ int maxn=-1000000000; while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); maxn=max(maxn,IntervalMax(1,idn[top[x]],idn[x])); x=fa[top[x]]; } if(deep[x]>deep[y]) swap(x,y); maxn=max(maxn,IntervalMax(1,idn[x],idn[y])); printf("%d\n",maxn); }
#include<bits/stdc++.h> using namespace std; const int M = 500500; typedef long long ll; struct EDGE{ll v,next;} e[M << 2]; struct TREE{ll l,r,lz; ll w;} t[M << 2]; ll n,m,head[M << 2],num,w[M],fa[M],top[M]; ll idn[M],val[M],son[M],siz[M],deep[M],cnt; void add(ll,ll); ll dfs1(ll,ll,ll); void dfs2(ll,ll); void build(ll,ll,ll); void update(ll); void down(ll); void SinglepointAdd(ll,ll,ll); void IntervalAdd(ll,ll,ll,ll); ll IntervalSum(ll,ll,ll); void TreeSum(ll x,ll y); int main(){ ios::sync_with_stdio(false); register int i,j; ll q,x,y; cin >> n >> m; for(i = 1; i <= n; ++i) cin >> w[i]; for(i = 1; i < n; ++i){ cin >> x >> y; add(x, y); add(y, x); } dfs1(1, 0, 1); dfs2(1, 1); build(1, n, 1); for(i = 1; i <= m; ++i){ cin >> q; if(q == 1){ cin >> x >> y; SinglepointAdd(1, idn[x], y); } else if(q == 2){ cin >> x >> y; IntervalAdd(1, idn[x], idn[x]+siz[x]-1, y); } else{ cin >> x; TreeSum(1, x); } } return 0; } void add(ll x,ll y){ e[++num].v = y; e[num].next = head[x]; head[x] = num; } ll dfs1(ll now,ll f,ll dp){ fa[now] = f; deep[now] = dp; siz[now] = 1; ll maxson = -1; for(register int i = head[now]; i; i = e[i].next){ if(f == e[i].v) continue; siz[now] += dfs1(e[i].v, now, dp+1); if(maxson < siz[e[i].v]){ maxson = siz[e[i].v]; son[now] = e[i].v; } } return siz[now]; } void dfs2(ll now,ll topx){ idn[now] = ++cnt; top[now] = topx; val[cnt] = w[now]; if(!son[now]) return; dfs2(son[now], topx); for(register int i = head[now]; i; i = e[i].next) if(!idn[e[i].v]) dfs2(e[i].v, e[i].v); } void build(ll l,ll r,ll u){ t[u].l = l,t[u].r = r; if(l == r){ t[u].w = val[l]; return; } ll m = (l + r) >> 1; build(l, m, u<<1); build(m+1, r, u<<1|1); update(u); } void update(ll u){ t[u].w = t[u << 1].w + t[u << 1 | 1].w; } void down(ll u){ t[u << 1].lz += t[u].lz; t[u << 1 | 1].lz += t[u].lz; t[u << 1].w += (t[u << 1].r - t[u << 1].l + 1) * t[u].lz; t[u << 1 | 1].w += (t[u << 1 | 1].r - t[u << 1 | 1].l + 1) * t[u].lz; t[u].lz = 0; } void SinglepointAdd(ll u,ll x,ll add){ if(t[u].l == x && t[u].l == t[u].r){ t[u].w += add; return; } if(t[u].lz) down(u); ll m = (t[u].l + t[u].r) >> 1; if(m >= x) SinglepointAdd(u << 1, x, add); if(m < x) SinglepointAdd(u << 1 | 1, x, add); update(u); } void IntervalAdd(ll u,ll l,ll r,ll add){ if(t[u].l >= l && t[u].r <= r){ t[u].w += (t[u].r - t[u].l + 1) * add; t[u].lz += add; return; } if(t[u].lz) down(u); ll m = (t[u].l + t[u].r) >> 1; if(m >= l) IntervalAdd(u << 1, l, r, add); if(m < r) IntervalAdd(u << 1 | 1, l, r, add); update(u); } ll IntervalSum(ll u,ll l,ll r){ ll ans=0; if(t[u].l >= l && t[u].r <= r) return t[u].w; if(t[u].lz) down(u); ll m = (t[u].l + t[u].r) >> 1; if(m >= l) ans += IntervalSum(u << 1, l, r); if(m < r) ans += IntervalSum(u << 1 | 1, l, r); return ans; } void TreeSum(ll x,ll y){ ll ans = 0; while(top[x] != top[y]){ if(deep[top[x]] < deep[top[y]]) swap(x,y); ans += IntervalSum(1, idn[top[x]], idn[x]); x = fa[top[x]]; } if(deep[x] > deep[y]) swap(x,y); ans += IntervalSum(1,idn[x],idn[y]); printf("%lld\n",ans); }