洛谷模板
#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
",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
",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
",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
",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
",ans);
}