BZOJ4127 : Abs
树链剖分+线段树。
线段树每个区间[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; }