[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
",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 MB
Submit: 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

Sample Output

10
13
9

HINT

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

原文地址:https://www.cnblogs.com/wang9897/p/10432849.html