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;
}

  

posted @ 2015-09-05 00:49  Claris  阅读(376)  评论(1编辑  收藏  举报