这就是线段树解决区间覆盖的一类毒瘤问题
自从xyz111在cf上出了那道线段树解决区间覆盖问题之后,这已经几乎成为了一种毒瘤算法,这道题可以说是有过之而无不及。首先我们考虑一个区间内有正有负,加完之后绝对值的和和三部分有关系1.有负数变成负数,2.由正数变成正数,3.有负数变成正数,前面两种非常好讨论,只有第三种有苦难。但是我们注意到第三种每个数字只会出现一次,所以就变成了区间覆盖的那一类问题,用区间覆盖线段树来解决,复杂度通过势能分析。
所以树链剖分之后随便搞一搞复杂度 $$ O(nlog^2n) $$
//coder : davidwang #include <cstdio> #include <cstdlib> #include <cstring> #include <vector> #include <iostream> #include <queue> #include <deque> #include <algorithm> using namespace std; #define LL long long #define X first #define Y second inline int read() { int ret=0,f=1; char ch; for (ch=getchar();ch>'9' || ch<'0';ch=getchar()) if (ch=='-') f=-f; for (;'0'<=ch && ch<='9';ch=getchar()) ret=ret*10+ch-'0'; return ret*f; } const int N = 100010; int son[N],fa[N],d[N],p[N][20],q[N],w[N],v[N],a[N],top[N],vis[N]; int start[N],to[N<<1],next[N<<1],size[N],cnt; inline void connect(int a,int b){ to[++cnt]=b; next[cnt]=start[a]; start[a]=cnt; } int n,m; struct node{ int l,r; int vmax,num; LL sum,flag; inline int mid(){ return r+l>>1; } inline int len(){ return r-l+1; } inline void add(LL x){ if (vmax!=0 && vmax+x>=0) printf("Wrong!!!\n"); if (vmax!=0) vmax+=x; flag+=x; sum+=x*(len()-num-num); } }s[N<<2]; void init(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(); m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<n;i++){ int x=read(),y=read(); connect(x,y); connect(y,x); } int head=0,tail=1,u; q[1]=1; d[1]=1; fa[1]=0; while (head<tail){ u=q[++head]; for (int p=start[u];p;p=next[p]){ int &v=to[p]; if (d[v]) continue; d[v]=d[u]+1; fa[v]=u; q[++tail]=v; } } for (int i=n;i;i--){ int x=q[i]; size[x]++; size[fa[x]]+=size[x]; if (size[son[fa[x]]]<size[x]) son[fa[x]]=x; } int now=0; for (int i=1;i<=n;i++){ int x=q[i]; if (vis[x]) continue; for (int j=x;j;j=son[j]){ top[j]=x; w[j]=++now; vis[j]=1; v[now]=a[j]; } } for (int i=1;i<=n;i++) p[i][0]=fa[i]; for (int j=1;j<20;j++) for (int i=1;i<=n;i++) p[i][j]=p[p[i][j-1]][j-1]; } inline int lca(int x,int y){ if (d[x]<d[y]) swap(x,y); int j; while (d[x]>d[y]){ for (j=1;d[p[x][j]]>=d[y];j++); x=p[x][j-1]; } while (x!=y){ for (j=1;p[x][j]!=p[y][j];j++); x=p[x][j-1],y=p[y][j-1]; } return x; } inline void push_down(int x){ if (s[x].r>s[x].l && s[x].flag){ s[x<<1].add(s[x].flag); s[x<<1|1].add(s[x].flag); s[x].flag=0; } } inline int gvmax(int x,int y){ if (x>=0) return y; if (y>=0) return x; return x>y?x:y; } inline void push_up(int x){ s[x].sum=s[x<<1].sum+s[x<<1|1].sum; s[x].num=s[x<<1].num+s[x<<1|1].num; s[x].vmax=gvmax(s[x<<1].vmax,s[x<<1|1].vmax); } inline void build(int i,int l,int r){ s[i].l=l; s[i].r=r; s[i].flag=0; if (l==r){ s[i].num=v[l]<0?1:0; s[i].vmax=min(0,v[l]); s[i].sum=abs(v[l]); return; } int m=l+r>>1; build(i<<1,l,m); build(i<<1|1,m+1,r); push_up(i); } inline LL query(int i,int l,int r){ if (s[i].l==l && s[i].r==r){ return s[i].sum; } push_down(i); int m=s[i].mid(); LL ret; if (r<=m) ret=query(i<<1,l,r); else if (l>m) ret=query(i<<1|1,l,r); else ret=query(i<<1,l,m)+query(i<<1|1,m+1,r); push_up(i); return ret; } inline void dfs(int i,int d){ if (s[i].vmax==0 || s[i].vmax+d<0){ s[i].add(d); return; } if (s[i].l==s[i].r){ s[i].sum=s[i].vmax+d; s[i].vmax=0; s[i].num=0; return; } push_down(i); dfs(i<<1,d); dfs(i<<1|1,d); push_up(i); } inline void modify(int i,int l,int r,int d){ if (s[i].l==l && s[i].r==r){ dfs(i,d); return; } push_down(i); int m=s[i].mid(); if (r<=m) modify(i<<1,l,r,d); else if (l>m) modify(i<<1|1,l,r,d); else modify(i<<1,l,m,d),modify(i<<1|1,m+1,r,d); push_up(i); } inline LL Query(int x,int y){ LL ans=0; int u=lca(x,y); while (d[x]>d[u]){ if (d[top[x]]>d[u]){ ans+=query(1,w[top[x]],w[x]); x=fa[top[x]]; }else{ ans+=query(1,w[son[u]],w[x]); x=u; } } swap(x,y); while (d[x]>d[u]){ if (d[top[x]]>d[u]){ ans+=query(1,w[top[x]],w[x]); x=fa[top[x]]; }else{ ans+=query(1,w[son[u]],w[x]); x=u; } } ans+=query(1,w[u],w[u]); return ans; } inline void Modify(int x,int y,int D){ int u=lca(x,y); while (d[x]>d[u]){ if (d[top[x]]>d[u]){ modify(1,w[top[x]],w[x],D); x=fa[top[x]]; }else{ modify(1,w[son[u]],w[x],D); x=u; } } swap(x,y); while (d[x]>d[u]){ if (d[top[x]]>d[u]){ modify(1,w[top[x]],w[x],D); x=fa[top[x]]; }else{ modify(1,w[son[u]],w[x],D); x=u; } } modify(1,w[u],w[u],D); return; } void work() { build(1,1,n); for (int i=1;i<=m;i++){ int op=read(),x=read(),y=read(); if (op==2){ printf("%lld\n",Query(x,y)); }else{ int d=read(); Modify(x,y,d); } } } int main() { init(); work(); return 0; }