bzoj 4127: Abs

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

Sample Output

10
13
9

HINT

对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8


因为负的数最多有n个。所以最多有n次从负数变成正数

那么我们只要维护下区间中负数的最大值。如果每次修改的时候如果加上x后变成正数了,那就暴力修改。因为最多n个负数所以复杂度最大是nlogn

然后剩下的就是直接区间加区间求和了

#include<cstdio>
using namespace std;
struct line
{
     int s,t;
     int next;
}a[200001];
int head[100001];
int edge;
inline void add(int s,int t)
{
	 a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
int son[100001],mson[100001],xson[100001],dep[100001];
int fa[100001],w[100001],px[100001],top[100001];
int tot;
int x[100001];
inline void dfs1(int d)
{
     int i;
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(t!=fa[d])
          {
               fa[t]=d;
               dfs1(t);
               son[d]+=son[t]+1;
               if(son[t]+1>mson[d])
               {
                    mson[d]=son[t]+1;
                    xson[d]=t;
               }
          }
     }
}
inline void dfs2(int d)
{
	 tot++;
	 w[d]=tot;
	 px[tot]=d;
     int i;
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(t==xson[d])
          {
          	   dep[t]=dep[d]+1;
               top[t]=top[d];
               dfs2(t);
          }
     }
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(t!=xson[d]&&t!=fa[d])
          {
          	   dep[t]=dep[d]+1;
               top[t]=t;
               dfs2(t);
          }
     }
}
struct tree
{
     int l,r;
     long long s1,s2;
     long long sx1,sx2;
     long long tag;
     int lo;
     int m;
}tr[800001];
inline void up(int p)
{
     tr[p].s1=tr[p*2].s1+tr[p*2+1].s1;
     tr[p].s2=tr[p*2].s2+tr[p*2+1].s2;
     tr[p].sx1=tr[p*2].sx1+tr[p*2+1].sx1;
     tr[p].sx2=tr[p*2].sx2+tr[p*2+1].sx2;
     if(tr[p*2].m>tr[p*2+1].m)
     {
          tr[p].m=tr[p*2].m;
          tr[p].lo=tr[p*2].lo;
     }
     else
     {
          tr[p].m=tr[p*2+1].m;
          tr[p].lo=tr[p*2+1].lo;
     }
}
inline void push(int p)
{
	 tr[p*2].s1+=(tr[p*2].sx1*tr[p].tag);
	 tr[p*2+1].s1+=(tr[p*2+1].sx1*tr[p].tag);
	 tr[p*2].s2-=(tr[p*2].sx2*tr[p].tag);
	 tr[p*2+1].s2-=(tr[p*2+1].sx2*tr[p].tag);
	 tr[p*2].m+=tr[p].tag;
	 tr[p*2+1].m+=tr[p].tag;
     tr[p*2].tag+=tr[p].tag;
     tr[p*2+1].tag+=tr[p].tag;
     tr[p].tag=0;
}
inline void build(int p,int l,int r)
{
     tr[p].l=l;
     tr[p].r=r;
     if(l!=r)
     {
          int mid=(l+r)/2;
          build(p*2,l,mid);
          build(p*2+1,mid+1,r);
          up(p);
     }
     else
     {
          if(x[px[l]]>=0)
          {
               tr[p].s1=x[px[l]];
               tr[p].sx1=1;
               tr[p].m=-2100000000;
          }
          else
          {
               tr[p].s2=-x[px[l]];
               tr[p].sx2=1;
               tr[p].m=x[px[l]];
               tr[p].lo=l;
          }
     }
}
inline tree cha(int p,int l,int r,long long x)
{
     if(l<=tr[p].l&&tr[p].r<=r)
          return tr[p];
     else
     {
     	  push(p);
          int mid=(tr[p].l+tr[p].r)/2;
          bool flag1=false,flag2=false;
          tree ans1,ans2,ans;
          if(l<=mid)
          {
               flag1=true;
               ans1=cha(p*2,l,r,x);
          }
          if(r>mid)
          {
               flag2=true;
               ans2=cha(p*2+1,l,r,x);
          }
          if(flag1)
          {
               if(flag2)
               {
                    if(ans1.m>ans2.m)
                    {
                         ans.m=ans1.m;
                         ans.lo=ans1.lo;
                    }
                    else
                    {
                         ans.m=ans2.m;
                         ans.lo=ans2.lo;
                    }
               }
               else
                    ans=ans1;
          }
          else
               ans=ans2;
          return ans;
     }
}
inline void changex(int p,int l,int r)
{
     if(l<=tr[p].l&&tr[p].r<=r)
     {
          tr[p].sx1=1;
          tr[p].sx2=0;
          tr[p].s1=tr[p].m;
          tr[p].s2=0;
          tr[p].m=-2100000000;
     }
     else
     {
     	  push(p);
          int mid=(tr[p].l+tr[p].r)/2;
          if(l<=mid)
               changex(p*2,l,r);
          if(r>mid)
               changex(p*2+1,l,r);
          up(p);
     }
}
inline void add(int p,int l,int r,int x)
{
     if(l<=tr[p].l&&tr[p].r<=r)
     {
          tr[p].tag+=x;
          tr[p].s1+=(tr[p].sx1*x);
          tr[p].s2-=(tr[p].sx2*x);
          tr[p].m+=x;
     }
     else
     {
     	  push(p);
          int mid=(tr[p].l+tr[p].r)/2;
          if(l<=mid)
               add(p*2,l,r,x);
          if(r>mid)
               add(p*2+1,l,r,x);
          up(p);
     }
}
inline long long ask(int p,int l,int r)
{
     if(l<=tr[p].l&&tr[p].r<=r)
          return tr[p].s1+tr[p].s2;
     else
     {
     	  push(p);
          int mid=(tr[p].l+tr[p].r)/2;
          long long ans=0;
          if(l<=mid)
               ans+=ask(p*2,l,r);
          if(r>mid)
               ans+=ask(p*2+1,l,r);
          //up(p);
          return ans;
     }
}
inline void change(int s,int t,long long x)
{
     int u=top[s],v=top[t];
     while(u!=v)
     {
          if(dep[u]>dep[v])
          {
          	   tree dx=cha(1,w[u],w[s],x);
               while(dx.m+x>0)
               {
                    changex(1,dx.lo,dx.lo);
                    dx=cha(1,w[u],w[s],x);
               }
               add(1,w[u],w[s],x);
               s=fa[top[s]];
          }
          else
          {
          	   tree dx=cha(1,w[v],w[t],x);
               while(dx.m+x>0)
               {
                    changex(1,dx.lo,dx.lo);
                    dx=cha(1,w[v],w[t],x);
               }
               add(1,w[v],w[t],x);
               t=fa[top[t]];
          }
          u=top[s];
          v=top[t];
     }
     if(dep[s]>dep[t])
     {
          tree dx=cha(1,w[t],w[s],x);
          while(dx.m+x>0)
          {
               changex(1,dx.lo,dx.lo);
               dx=cha(1,w[t],w[s],x);
          }
          add(1,w[t],w[s],x);
     }
     else
     {
          tree dx=cha(1,w[s],w[t],x);
          while(dx.m+x>0)
          {
               changex(1,dx.lo,dx.lo);
               dx=cha(1,w[s],w[t],x);
          }
          add(1,w[s],w[t],x);
     }
}
inline long long sum(int s,int t)
{
     int u=top[s],v=top[t];
     long long ans=0;
     while(u!=v)
     {
          if(dep[u]>dep[v])
          {
               ans+=ask(1,w[u],w[s]);
               s=fa[top[s]];
          }
          else
          {
               ans+=ask(1,w[v],w[t]);
               t=fa[top[t]];
          }
          u=top[s];
          v=top[t];
     }
     if(dep[s]>dep[t])
          ans+=ask(1,w[t],w[s]);
     else
          ans+=ask(1,w[s],w[t]);
     return ans;
}
int main()
{
     int n,m;
     scanf("%d%d",&n,&m);
     int i,s,t,xx;
     for(i=1;i<=n;i++)
          scanf("%d",&x[i]);
     for(i=1;i<=n-1;i++)
     {
          scanf("%d%d",&s,&t);
          edge++;
          add(s,t);
          edge++;
          add(t,s);
     }
     dfs1(1);
     dfs2(1);
     build(1,1,tot);
     for(i=1;i<=m;i++)
     {
          scanf("%d",&xx);
          if(xx==1)
          {
               scanf("%d%d%d",&s,&t,&xx);
               change(s,t,xx);
          }
          else
          {
               scanf("%d%d",&s,&t);
               printf("%lld\n",sum(s,t));
          }
     }
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值