题解: 我们考虑 $ d>0 $ 然后对于每一个负数 只有一次从负数到正数的变化 所以我们考虑 把每一个临界点的修改都拿出来暴力改掉 然后维护答案就行
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=3e5+10;
const double eps=1e-8;
#define ll long long
using namespace std;
const ll inf=2e18;
struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int fa[MAXN],dep[MAXN],son[MAXN],num[MAXN],n,m,a[MAXN];
void dfs1(int x,int pre,int deep){
dep[x]=deep+1;fa[x]=pre;num[x]=1;
link(x){
if(j->t==pre)continue;
dfs1(j->t,x,deep+1);
num[x]+=num[j->t];
if(son[x]==-1||num[son[x]]<num[j->t])son[x]=j->t;
}
}
int p[MAXN],fp[MAXN],cnt,tp[MAXN];
void dfs2(int x,int td){
tp[x]=td;p[x]=++cnt;fp[p[x]]=x;
if(son[x]!=-1)dfs2(son[x],td);
link(x)if(j->t!=fa[x]&&j->t!=son[x])dfs2(j->t,j->t);
}
ll maxx[MAXN<<2],Num[MAXN<<2];
ll tag[MAXN<<2],sum[MAXN<<2];
void up(int x){
maxx[x]=max(maxx[x<<1],maxx[x<<1|1]);
sum[x]=sum[x<<1]+sum[x<<1|1];
Num[x]=Num[x<<1]+Num[x<<1|1];
}
void push(int x,int l,int r){
if(tag[x]){
int mid=(l+r)>>1;
tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];
if(maxx[x<<1]!=-inf)maxx[x<<1]+=tag[x];
if(maxx[x<<1|1]!=-inf)maxx[x<<1|1]+=tag[x];
sum[x<<1]+=tag[x]*(mid-l+1-2*Num[x<<1]);
sum[x<<1|1]+=tag[x]*(r-mid-2*Num[x<<1|1]);
tag[x]=0;
}
}
void built(int x,int l,int r){
sum[x]=tag[x]=0;
if(l==r){
if(a[fp[l]]<0)Num[x]=1,maxx[x]=a[fp[l]],sum[x]=-a[fp[l]];
else Num[x]=0,maxx[x]=-inf,sum[x]=a[fp[l]];
return ;
}
int mid=(l+r)>>1;
built(x<<1,l,mid);
built(x<<1|1,mid+1,r);
up(x);
}
void update(int x,int l,int r,int t,int k){
if(l==r){
Num[x]=0;maxx[x]=-inf;sum[x]=k;
return ;
}
int mid=(l+r)>>1;
push(x,l,r);
if(t<=mid)update(x<<1,l,mid,t,k);
else update(x<<1|1,mid+1,r,t,k);
up(x);
}
void update1(int x,int l,int r,int ql,int qr,int t){
if(ql<=l&&r<=qr){
tag[x]+=t;sum[x]+=1ll*t*(r-l+1-2*Num[x]);
if(maxx[x]!=-inf)maxx[x]+=t;
return ;
}
int mid=(l+r)>>1;
push(x,l,r);
if(ql<=mid)update1(x<<1,l,mid,ql,qr,t);
if(qr>mid)update1(x<<1|1,mid+1,r,ql,qr,t);
up(x);
}
ll ans;
void query(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){ans+=sum[x];return ;}
int mid=(l+r)>>1;
push(x,l,r);
if(ql<=mid)query(x<<1,l,mid,ql,qr);
if(qr>mid)query(x<<1|1,mid+1,r,ql,qr);
up(x);
}
vector<pii>vec;
void query1(int x,int l,int r,int ql,int qr,int d){
if(ql<=l&&r<=qr){
if(maxx[x]<-d)return ;
if(l==r){vec.pb(mp(l,maxx[x]));return ;}
}
int mid=(l+r)>>1;
push(x,l,r);
if(ql<=mid)query1(x<<1,l,mid,ql,qr,d);
if(qr>mid)query1(x<<1|1,mid+1,r,ql,qr,d);
up(x);
}
void solve(int x,int y,int d){
vec.clear();
query1(1,1,n,x,y,d);
//for(int i=0;i<vec.size();i++)cout<<vec[i].first<<":::";
//cout<<endl;
int l=x;
for(int i=0;i<vec.size();i++){
update(1,1,n,vec[i].first,d+vec[i].second);
if(l<vec[i].first)update1(1,1,n,l,vec[i].first-1,d);
l=vec[i].first+1;
}
if(l<=y)update1(1,1,n,l,y,d);
}
void work1(int u,int v,int d){
int uu=tp[u];int vv=tp[v];
while(uu!=vv){
if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
solve(p[uu],p[u],d);
u=fa[uu];uu=tp[u];
}
if(dep[u]>dep[v])swap(u,v);
solve(p[u],p[v],d);
}
void work2(int u,int v){
int uu=tp[u];int vv=tp[v];
ll ans1=0;
while(uu!=vv){
if(dep[uu]<dep[vv])swap(u,v),swap(uu,vv);
ans=0;query(1,1,n,p[uu],p[u]);ans1+=ans;
u=fa[uu];uu=tp[u];
}
if(dep[u]>dep[v])swap(u,v);
ans=0;query(1,1,n,p[u],p[v]);ans1+=ans;
printf("%lld\n",ans1);
}
int main(){
n=read();m=read();
inc(i,1,n)a[i]=read(),son[i]=-1;
int x,y,d;
inc(i,2,n)x=read(),y=read(),add(x,y),add(y,x);
dfs1(1,0,0);dfs2(1,1);
built(1,1,n);
int op;
while(m--){
op=read();x=read();y=read();
if(op==1)d=read(),work1(x,y,d);
else work2(x,y);
}
return 0;
}
4127: Abs
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 765 Solved: 261
[Submit][Status][Discuss]
Description
给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和
Input
第一行两个整数n和m,表示结点个数和操作数
接下来一行n个整数a_i,表示点i的权值 接下来n-1行,每行两个整数u,v表示存在一条(u,v)的边 接下来m行,每行一个操作,输入格式见题目描述
Output
对于每个询问输出答案
Sample Input
4 4
-4 1 5 -2
1 2
2 3
3 4
2 1 3
1 1 4 3
2 1 3
2 3 4
-4 1 5 -2
1 2
2 3
3 4
2 1 3
1 1 4 3
2 1 3
2 3 4
Sample Output
10
13
9
13
9
HINT
对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8