【TJOI2015】旅游

传送门

 

链剖裸题。只不过码量很大。注意细节就好。

答案分三种情况:在起点到lca之间;在lca到终点之间;在lca两侧。

 

 

之前犯了一个错误:求一个区间内部的极差的时候求错了

int shang(int root,int l,int r){
    if(T[root].l>=l&&T[root].r<=r)
        return T[root].ansl;
    pushdown(root);
    int ret=0;
    if(l<=mid) ret=max(ret,shang(lc,l,r));
    if(r> mid) ret=max(ret,shang(rc,l,r));
    return ret;
}
int xia(int root,int l,int r){
    if(T[root].l>=l&&T[root].r<=r)
        return T[root].ansr;
    pushdown(root);
    int ret=0;
    if(l<=mid) ret=max(ret,xia(lc,l,r));
    if(r> mid) ret=max(ret,xia(rc,l,r));
    return ret;
}

 

这里应该用线段树合并!!

#include<bits/stdc++.h>
#define mid ((T[root].l+T[root].r)>>1)
#define lc (root<<1)
#define rc (root<<1|1)
using namespace std;
const int maxn=5e4+10;
const int oo=1<<30;
int Head[maxn],Next[maxn<<1],V[maxn<<1],cnt=0;
int t[maxn],dfn[maxn],son[maxn],siz[maxn],dep[maxn],tp[maxn],fa[maxn],tot=0;
int n,q,val[maxn],x,y,v;
struct node{
	int l,r,lz,mx,mn,ansl,ansr;
	node(){lz=mx=ansl=ansr=0;mn=oo;}
}T[maxn<<2];
inline void add(int u,int v){
	++cnt;
	Next[cnt]=Head[u];
	V[cnt]=v;
	Head[u]=cnt;
}
inline int read(){
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return x;
}
void dfs1(int u,int f){
	son[u]=0,siz[u]=1,fa[u]=f,dep[u]=dep[f]+1;
	for(int i=Head[u];i;i=Next[i]) if(V[i]!=f){
		dfs1(V[i],u);
		siz[u]+=siz[V[i]];
		if(siz[V[i]]>siz[son[u]]) son[u]=V[i];
	}
}
void dfs2(int u,int top){
	t[dfn[u]=++tot]=u,tp[u]=top;
	if(son[u]) dfs2(son[u],top);
	for(int i=Head[u];i;i=Next[i])
	if(V[i]!=fa[u]&&V[i]!=son[u])
		dfs2(V[i],V[i]);
}
inline void pushup(int root){
	T[root].mx=max(T[lc].mx,T[rc].mx),T[root].mn=min(T[lc].mn,T[rc].mn);
	T[root].ansl=max(max(T[lc].ansl,T[rc].ansl),T[lc].mx-T[rc].mn);
	T[root].ansr=max(max(T[lc].ansr,T[rc].ansr),T[rc].mx-T[lc].mn);
}
inline void pushnow(int root,int v){T[root].mx+=v,T[root].mn+=v,T[root].lz+=v;}
inline void pushdown(int root){if(T[root].lz) pushnow(lc,T[root].lz),pushnow(rc,T[root].lz),T[root].lz=0;}
void build(int root,int l,int r){
	T[root].l=l,T[root].r=r;
	if(l==r){T[root].mx=T[root].mn=val[t[l]];return;}
	build(lc,l,mid),build(rc,mid+1,r);
	pushup(root);
}
void change(int root,int l,int r,int v){
	if(T[root].l>=l&&T[root].r<=r){
		pushnow(root,v);
		return;
	}
	pushdown(root);
	if(l<=mid) change(lc,l,r,v);
	if(r> mid) change(rc,l,r,v);
	pushup(root);
}
void update(int x,int y,int w){
	while(tp[x]!=tp[y]){
		if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
		change(1,dfn[tp[x]],dfn[x],w);
		x=fa[tp[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	change(1,dfn[y],dfn[x],w);
}

node Merge(node p1,node p2){
	node ret;
	ret.mx=max(p1.mx,p2.mx),ret.mn=min(p1.mn,p2.mn);
	ret.ansl=max(max(p1.ansl,p2.ansl),p1.mx-p2.mn);//start->lca
	ret.ansr=max(max(p1.ansr,p2.ansr),p2.mx-p1.mn);//end->lca
	return ret;
}
node get(int root,int l,int r){
	if(T[root].l>=l&&T[root].r<=r)
		return T[root];
	pushdown(root);
	if(l>mid) return get(rc,l,r);
	if(r<=mid) return get(lc,l,r);
	return Merge(get(lc,l,r),get(rc,l,r));
}
int getlca(int x,int y){
	while(tp[x]!=tp[y]){
		if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
		x=fa[tp[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	return y;
}
int query(int x,int y){
	int g=getlca(x,y);
	node L,R;
	while(tp[x]!=tp[g]) L=Merge(get(1,dfn[tp[x]],dfn[x]),L),x=fa[tp[x]];
	L=Merge(get(1,dfn[g],dfn[x]),L);
	while(tp[y]!=tp[g]) R=Merge(get(1,dfn[tp[y]],dfn[y]),R),y=fa[tp[y]];
	R=Merge(get(1,dfn[g],dfn[y]),R);
	return max(max(L.ansl,R.ansr),R.mx-L.mn);
}
inline void print(int x){
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
int main(){
	n=read();
	for(int i=1;i<=n;++i) val[i]=read();
	for(int i=1;i<n;++i) x=read(),y=read(),add(x,y),add(y,x);
	dfs1(1,0),dfs2(1,1),build(1,1,tot);
	q=read();
	while(q--){
		x=read(),y=read(),v=read();
		print(query(x,y)),putchar('\n');
		update(x,y,v);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值