树链剖分+线段树。
线段树每个区间[l,r]维护:
m:最大的负数
s:所有数字绝对值的和
d:正数的个数-负数的个数
t:懒惰标记
区间修改时,若最大的负数<0且最大的负数+p>=0,则暴力递归,否则打标记。
因为每个负数只会被暴力修改一次,所以时间复杂度为$O(n\log^2n)$。
#include<cstdio>
#define N 100010
typedef long long ll;
int n,m,i,op,x,y,z,a[N];ll ans;
int g[N],v[N<<1],nxt[N<<1],ed,size[N],son[N],f[N],d[N],top[N],loc[N],dfn,seq[N];
struct P{
ll m,s,t;int d;
P(){}
inline void set(int x){
t=0;
if(x<0)m=x,s=-x,d=-1;else m=0,s=x,d=1;
}
}T[262145];
inline int merge(int a,int b){
if(a>=0&&b>=0)return 0;
if(a>=0)return b;
if(b>=0)return a;
return a>b?a:b;
}
inline void add1(int x,ll p){
T[x].m+=p;
T[x].s+=p*T[x].d;
T[x].t+=p;
}
inline void pb(int x){if(T[x].t)add1(x<<1,T[x].t),add1(x<<1|1,T[x].t),T[x].t=0;}
inline void up(int x){
T[x].m=merge(T[x<<1].m,T[x<<1|1].m);
T[x].s=T[x<<1].s+T[x<<1|1].s;
T[x].d=T[x<<1].d+T[x<<1|1].d;
}
void build(int x,int a,int b){
if(a==b){T[x].set(seq[a]);return;}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b),up(x);
}
void change(int x,int a,int b,int c,int d,int p){
if(c<=a&&b<=d&&(T[x].m>=0||T[x].m+p<0)){add1(x,p);return;}
if(a==b){T[x].set(T[x].m+p);return;}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)change(x<<1,a,mid,c,d,p);
if(d>mid)change(x<<1|1,mid+1,b,c,d,p);
up(x);
}
void ask(int x,int a,int b,int c,int d){
if(c<=a&&b<=d){ans+=T[x].s;return;}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)ask(x<<1,a,mid,c,d);
if(d>mid)ask(x<<1|1,mid+1,b,c,d);
up(x);
}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x,int y){
size[x]=1,d[x]=d[f[x]=y]+1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=y){
dfs(v[i],x);size[x]+=size[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
top[x]=y;seq[loc[x]=++dfn]=a[x];
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
}
inline void modify(int x,int y,int p){
for(;top[x]!=top[y];x=f[top[x]]){
if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
change(1,1,n,loc[top[x]],loc[x],p);
}
if(d[x]<d[y]){int z=x;x=y;y=z;}
change(1,1,n,loc[y],loc[x],p);
}
inline void query(int x,int y){
for(ans=0;top[x]!=top[y];x=f[top[x]]){
if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
ask(1,1,n,loc[top[x]],loc[x]);
}
if(d[x]<d[y]){int z=x;x=y;y=z;}
ask(1,1,n,loc[y],loc[x]);
printf("%lld\n",ans);
}
inline void read(int&a){char c;while(!(((c=getchar())>=‘0‘)&&(c<=‘9‘)));a=c-‘0‘;while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;}
inline void read2(int&a){
char c;bool f=0;a=0;
while(!((((c=getchar())>=‘0‘)&&(c<=‘9‘))||(c==‘-‘)));
if(c!=‘-‘)a=c-‘0‘;else f=1;
while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;
if(f)a=-a;
}
int main(){
read(n),read(m);
for(i=1;i<=n;i++)read2(a[i]);
for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
dfs(1,0),dfs2(1,1),build(1,1,n);
while(m--){
read(op),read(x),read(y);
if(op==1)read(z),modify(x,y,z);else query(x,y);
}
return 0;
}
原文:http://www.cnblogs.com/clrs97/p/4782646.html