【BZOJ4127】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

Source

SDOIRound2之前模拟赛zky学长出的题
当时考场上想出了标算但是写残了TAT
如今终于不写残了
当时感觉有点像花神游历各国所以考虑记录区间最大负整数然后暴力下放之类的balabala
然而正解并不是这个
其实正解是整体二分二分每个点大于零的时间然后树剖

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define lchild rt<<1,l,mid
#define rchild rt<<1|1,mid+1,r
#define ln rt<<1
#define rn rt<<1|1
#define MAXN 100010
#define MAXINT 0x7fffffff
#define LL long long
#define GET (ch>='0'&&ch<='9')
using namespace std;
int n,m,top,Top;
int val[MAXN],size[MAXN],deep[MAXN],chain[MAXN],num[MAXN],Val[MAXN],fa[MAXN];
struct seg
{
    int l,r;
    LL sum,maxn,delta,flag;
    void insert(int x)
    {
        if (x<0)    maxn=x,sum=-x,flag=-1;
        else    maxn=0,sum=x,flag=1;delta=0;
    }
}tree[MAXN<<2];
struct edge
{
    int to;
    edge *next;
}e[MAXN<<1],*prev[MAXN];
void insert(int u,int v)    {e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];}
void in(int &x)
{
    char ch=getchar();x=0;int flag=1;
    while (!GET)    flag=ch=='-'?-1:1,ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
void dfs1(int x,int f)
{
    size[x]=1;fa[x]=f;
    for (edge *i=prev[x];i;i=i->next)   if (i->to!=f)   deep[i->to]=deep[x]+1,dfs1(i->to,x),size[x]+=size[i->to];
}
void dfs2(int x,int last)
{
    chain[x]=last;num[x]=++Top;Val[num[x]]=val[x];int t=0;
    for (edge *i=prev[x];i;i=i->next)   if (deep[i->to]>deep[x]&&size[i->to]>size[t])   t=i->to;
    if (!t) return;dfs2(t,last);
    for (edge *i=prev[x];i;i=i->next)   if (deep[i->to]>deep[x]&&i->to!=t)  dfs2(i->to,i->to);
}
LL Min(LL a,LL b)
{
    if (a>=0&&b>=0) return 0;
    if (a>=0||b>=0) return min(a,b);
    return max(a,b);
}
void push_up(int rt)
{
    tree[rt].maxn=Min(tree[ln].maxn,tree[rn].maxn);
    tree[rt].sum=tree[ln].sum+tree[rn].sum;
    tree[rt].flag=tree[ln].flag+tree[rn].flag;
}
void push_down(int rt)
{
    if (tree[rt].l==tree[rt].r||tree[rt].delta==0)  return;
    tree[ln].maxn+=tree[rt].delta;tree[ln].sum+=tree[ln].flag*tree[rt].delta;tree[ln].delta+=tree[rt].delta;
    tree[rn].maxn+=tree[rt].delta;tree[rn].sum+=tree[rn].flag*tree[rt].delta;tree[rn].delta+=tree[rt].delta;
    tree[rt].delta=0;
}
void build(int rt=1,int l=1,int r=n)
{
    tree[rt].l=l;tree[rt].r=r;
    if (l==r)   {tree[rt].insert(Val[l]);return;}
    int mid=(l+r)>>1;build(lchild);build(rchild);push_up(rt);
}
void modify(int rt,int l,int r,int delta)
{
    int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
    if (l<=L&&r>=R&&(tree[rt].maxn>=0||tree[rt].maxn+delta<0))  {tree[rt].maxn+=delta;tree[rt].sum+=(LL)tree[rt].flag*delta;tree[rt].delta+=delta;return;}
    if (L==R)   {tree[rt].insert(tree[rt].maxn+delta);return;}
    push_down(rt);
    if (r<=mid) modify(ln,l,r,delta);
    else    if (l>mid)  modify(rn,l,r,delta);
    else    modify(ln,l,mid,delta),modify(rn,mid+1,r,delta);
    push_up(rt);
}
LL query(int rt,int l,int r)
{
    push_down(rt);
    int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
    if (l<=L&&r>=R) return tree[rt].sum;
    if (r<=mid) return query(ln,l,r);
    if (l>mid)  return query(rn,l,r);
    return query(ln,l,mid)+query(rn,mid+1,r);
}
void Modify(int a,int b,int delta)
{
    while (chain[a]!=chain[b])
    {
        if (deep[chain[a]]<deep[chain[b]])  swap(a,b);
        modify(1,num[chain[a]],num[a],delta);a=fa[chain[a]];
    }
    if (deep[a]<deep[b])    swap(a,b);modify(1,num[b],num[a],delta);
}
LL Query(int a,int b)
{
    LL ret=0;
    while (chain[a]!=chain[b])
    {
        if (deep[chain[a]]<deep[chain[b]])  swap(a,b);
        ret+=query(1,num[chain[a]],num[a]);a=fa[chain[a]];
    }
    if (deep[a]<deep[b])    swap(a,b);ret+=query(1,num[b],num[a]);return ret;
}
int main()
{
    in(n);in(m);int opt,u,v,d;
    for (int i=1;i<=n;i++)  in(val[i]);
    for (int i=1;i<n;i++)   in(u),in(v),insert(u,v),insert(v,u);
    dfs1(1,0);dfs2(1,1);build();
    while (m--)
    {
        in(opt);in(u);in(v);
        if (opt==1) in(d),Modify(u,v,d);
        else    printf("%lld\n",Query(u,v));
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值