[BZOJ]4127: Abs
题解: 我们考虑 $ 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