[bzoj4127]Abs

先树链剖分,开一棵线段树维护区间:1.abs的和;2.正数的数量-负数的数量;3.最大的负数。

询问就可以直接处理,考虑修改操作,对于一个区间,如果最大的负数+d变为了正数,就暴力修改下去,否则直接修改13两个信息并打上懒标记。因为d是非负的,所以每一个节点最多修改一次,时间复杂度不变。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 100005
  4 #define mid (l+r>>1)
  5 #define L (k<<1)
  6 #define R (L+1)
  7 #define ll long long
  8 struct ji{
  9     int nex,to;
 10 }edge[N<<1];
 11 int E,V,n,m,p,x,y,z,w[N],head[N],fa[N],sh[N],sz[N],ma[N],top[N],id[N],id2[N],zf[N<<2],mf[N<<2];
 12 ll f[N<<2],laz[N<<2];
 13 void add(int x,int y){
 14     edge[E].nex=head[x];
 15     edge[E].to=y;
 16     head[x]=E++;
 17 }
 18 void update(int k,ll p){
 19     mf[k]+=p;
 20     f[k]+=p*zf[k];
 21     laz[k]+=p;
 22 }
 23 void up(int k){
 24     mf[k]=max(mf[L],mf[R])+laz[k];
 25     f[k]=f[L]+f[R]+laz[k]*zf[k];
 26     zf[k]=zf[L]+zf[R];
 27 }
 28 void down(int k){
 29     update(L,laz[k]);
 30     update(R,laz[k]);
 31     laz[k]=0;
 32 }
 33 void build(int k,ll p){
 34     f[k]=abs(p);
 35     zf[k]=2*(p>0)-1;
 36     if (p>0)mf[k]=-0x3f3f3f3f;
 37     else mf[k]=p;
 38 }
 39 void build(int k,int l,int r){
 40     if (l==r){
 41         build(k,w[id2[l]]);
 42         return;
 43     }
 44     build(L,l,mid);
 45     build(R,mid+1,r);
 46     up(k);
 47 }
 48 void update(int k,int l,int r,int x,int y,int z){
 49     if ((l>y)||(x>r))return;
 50     if (l==r){
 51         build(k,f[k]*zf[k]+z);
 52         return;
 53     }
 54     if ((x<=l)&&(r<=y)&&(mf[k]+z<=0)){
 55         update(k,z);
 56         return;
 57     }
 58     down(k);
 59     update(L,l,mid,x,y,z);
 60     update(R,mid+1,r,x,y,z);
 61     up(k);
 62 }
 63 ll query(int k,int l,int r,int x,int y){
 64     if ((x>r)||(l>y))return 0;
 65     if ((x<=l)&&(r<=y))return f[k];
 66     down(k);
 67     return query(L,l,mid,x,y)+query(R,mid+1,r,x,y);
 68 }
 69 void dfs(int k,int f,int s){
 70     fa[k]=f;
 71     sz[k]=1;
 72     sh[k]=s;
 73     for(int i=head[k];i!=-1;i=edge[i].nex)
 74         if (edge[i].to!=f){
 75             dfs(edge[i].to,k,s+1);
 76             sz[k]+=sz[edge[i].to];
 77             if (sz[ma[k]]<sz[edge[i].to])ma[k]=edge[i].to;
 78         }
 79 }
 80 void dfs2(int k,int t){
 81     id[k]=++x;
 82     id2[x]=k;
 83     top[k]=t;
 84     if (ma[k])dfs2(ma[k],t);
 85     for(int i=head[k];i!=-1;i=edge[i].nex)
 86         if ((edge[i].to!=fa[k])&&(edge[i].to!=ma[k]))dfs2(edge[i].to,edge[i].to);
 87 }
 88 ll calc(int x,int y){
 89     ll ans=0;
 90     while (top[x]!=top[y]){
 91         if (sh[top[x]]<sh[top[y]])swap(x,y);
 92         ans+=query(1,1,n,id[top[x]],id[x]);
 93         x=fa[top[x]];
 94     }
 95     if (sh[x]>sh[y])swap(x,y);
 96     return ans+query(1,1,n,id[x],id[y]);
 97 }
 98 void update(int x,int y,int z){
 99     while (top[x]!=top[y]){
100         if (sh[top[x]]<sh[top[y]])swap(x,y);
101         update(1,1,n,id[top[x]],id[x],z);
102         x=fa[top[x]];
103     }
104     if (sh[x]>sh[y])swap(x,y);
105     update(1,1,n,id[x],id[y],z);
106 }
107 int main(){
108     scanf("%d%d",&n,&m);
109     memset(head,-1,sizeof(head));
110     for(int i=1;i<=n;i++)scanf("%d",&w[i]);
111     for(int i=1;i<n;i++){
112         scanf("%d%d",&x,&y);
113         add(x,y);
114         add(y,x);
115     }
116     dfs(1,1,0);
117     x=0;
118     dfs2(1,1);
119     build(1,1,n);
120     for(int i=1;i<=m;i++){
121         scanf("%d%d%d",&p,&x,&y);
122         if (p==2)printf("%lld\n",calc(x,y));
123         else{
124             scanf("%d",&z);
125             update(x,y,z);
126         }
127     }
128 }
View Code

 

posted @ 2019-07-28 10:31  PYWBKTDA  阅读(121)  评论(0编辑  收藏  举报