[TJOI2015]旅游 [树链剖分神题]

传送门

第一眼看是树剖加链上最大最小 , 但必须保证最小出现在最大之前

于是我们考虑直接维护一个区间最大最小的差 (保证最小在最大之前)

我们发现,这个差就是 Max[rc]-Min[lc]

等等,我们从下往上走和从上往下方向不同(废话)

也就是说我们从下往上要用的是上面的最大-下面的最小

反之则是下面的最大-上面的最小

于是我们考虑维护两个(lval,rval)

t[x].lval = max( max(t[x<<1].lval , t[x<<1|1].lval) , t[x<<1|1].Max - t[x<<1].Min);

t[x].rval = max( max(t[x<<1].rval , t[x<<1|1].rval) , t[x<<1].Max - t[x<<1|1].Min);

然后考虑树剖时如何合并??

我们将最大最小存在数组里 , 然后O(个数^2)扫一遍更新ans

因为重链+轻链的个数<log(n) , 所以总复杂度为O(nlogn^2)

为了方便 , 我们先处理x到lca的 , 再处理lca到y的

我们还需要记录x到lca的最小, 与lca到y的最大,然后再打一下擂台

因为答案可能在两条路径上


//写过的最长代码 (170)
#include<bits/stdc++.h>
#define N 50050
#define M N*2
#define LL long long
#define inf 0x3fffffff
using namespace std;
int first[N],next[M],to[M],tot;
int fa[N],son[N],id[N],dep[N];
int sign,top[N],siz[N],pre[N];
int n,a[N],m; LL ans,Max[25],Min[25],tmp;
struct Node{
	int l,r; 
	LL tag,Min,Max;
	LL lval,rval; 
}t[N<<2];
void add(int x,int y){
	next[++tot]=first[x],first[x]=tot,to[tot]=y;
}
void dfs1(int u,int f){
	siz[u]=1;
	for(int i=first[u];i;i=next[i]){
		int t=to[i]; if(t==f) continue;
		fa[t]=u,dep[t]=dep[u]+1; dfs1(t,u); siz[u]+=siz[t];
		if(siz[t]>siz[son[u]]) son[u]=t; 
	}
}
void dfs2(int u,int Top){
	id[u]=++sign,top[u]=Top,pre[sign]=u;
	if(son[u]) dfs2(son[u],Top);
	for(int i=first[u];i;i=next[i])
		if(to[i]!=fa[u] && to[i]!=son[u]) dfs2(to[i],to[i]);
}
/*----------------------------------------线段树-------------------------------------*/
void Pushup(int x){
	t[x].Max = max(t[x<<1].Max , t[x<<1|1].Max);
	t[x].Min = min(t[x<<1].Min , t[x<<1|1].Min);
	t[x].lval = max( max(t[x<<1].lval , t[x<<1|1].lval) , t[x<<1|1].Max - t[x<<1].Min);
	t[x].rval = max( max(t[x<<1].rval , t[x<<1|1].rval) , t[x<<1].Max - t[x<<1|1].Min);
}
void Pushdown(int x){
	if(t[x].tag){
		t[x<<1].Min += t[x].tag;
		t[x<<1|1].Min += t[x].tag;
		t[x<<1].Max += t[x].tag;
		t[x<<1|1].Max += t[x].tag;
		t[x<<1].tag += t[x].tag;
		t[x<<1|1].tag += t[x].tag;
		t[x].tag = 0;  
	}
}
void build(int x,int l,int r){
	t[x].l=l,t[x].r=r;
	if(l==r){t[x].Min=t[x].Max=a[pre[l]]; return;}
	int mid=(l+r)>>1;
	build(x<<1,l,mid),build(x<<1|1,mid+1,r);
	Pushup(x);
}
void quary(int x,int L,int R,Node &k){
	if(L<=t[x].l && t[x].r<=R){
		k.lval = max(k.lval,t[x].lval);
		k.rval = max(k.rval,t[x].rval);
		k.Max = max(k.Max,t[x].Max);
		k.Min = min(k.Min,t[x].Min);
		return;
	}
	Pushdown(x);
	int mid=(t[x].l+t[x].r)>>1;
	if(L>mid) quary(x<<1|1,L,R,k);
	else if(R<=mid) quary(x<<1,L,R,k);
	else{
		Node a,b; 
		a.Min=inf , a.Max=a.lval=a.rval=0;
		b.Min=inf , b.Max=b.lval=b.rval=0;
		quary(x<<1,L,R,a);
		quary(x<<1|1,L,R,b);
		k.lval = max(a.lval,b.lval);
		k.rval = max(a.rval,b.rval);
		k.lval = max(k.lval , b.Max-a.Min);
		k.rval = max(k.rval , a.Max-b.Min);
		k.Max = max(a.Max,b.Max);
		k.Min = min(a.Min,b.Min);
	}
}
void update(int x,int L,int R,int val){
	if(L<=t[x].l && t[x].r<=R){
		t[x].tag += val;  
		t[x].Min += val , t[x].Max += val;
		return;
	}
	Pushdown(x);
	int mid=(t[x].l+t[x].r)>>1;
	if(L<=mid) update(x<<1,L,R,val);
	if(R>mid) update(x<<1|1,L,R,val);
	Pushup(x);
}
/*-------------------------------------树剖--------------------------------*/
int lca(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]<=dep[y]) swap(x,y);
	return y; 
}
void Q1(int x,int goal){
	int c1=0; Node now; tmp=inf;
	now.Min=inf , now.Max=now.lval=now.rval=0;
	while(top[x]!=top[goal]){
		now.Min=inf , now.Max=now.lval=now.rval=0;
		quary(1,id[top[x]],id[x],now); 
		ans = max(ans , now.rval);
		Max[++c1] = now.Max;
		Min[c1] = now.Min;
		x=fa[top[x]];
	}
	now.Min=inf , now.Max=now.lval=now.rval=0;
	quary(1,id[goal],id[x],now);
	ans = max(ans , now.rval);
	Max[++c1] = now.Max;
	Min[c1] = now.Min;
	for(int i=1;i<c1;i++) for(int j=i+1;j<=c1;j++) ans = max(ans , Max[j]-Min[i]);
	for(int i=1;i<=c1;i++) tmp = min(tmp,Min[i]); 
}
void Q2(int x,int goal){
	int c1=0;  Node now; 
	now.Min=inf , now.Max=now.lval=now.rval=0;
	while(top[x]!=top[goal]){
		now.Min=inf , now.Max=now.lval=now.rval=0;
		quary(1,id[top[x]],id[x],now); 
		ans = max(ans , now.lval);
		Max[++c1] = now.Max;
		Min[c1] = now.Min;
		x=fa[top[x]];
	}
	now.Min=inf , now.Max=now.lval=now.rval=0;
	quary(1,id[goal],id[x],now); 
	ans = max(ans , now.lval);
	Max[++c1] = now.Max;
	Min[c1] = now.Min;
	for(int i=1;i<c1;i++) for(int j=i+1;j<=c1;j++) ans = max(ans , Max[i]-Min[j]);
	for(int i=1;i<=c1;i++) ans = max(ans,Max[i]-tmp);
}
void Update(int x,int y,int val){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		update(1,id[top[x]],id[x],val);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y]) swap(x,y);
	update(1,id[y],id[x],val);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n-1;i++){
		int x,y; scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	dep[1]=1,dfs1(1,0),dfs2(1,1),build(1,1,n);
	scanf("%d",&m); while(m--){
		Node now;now.Min=inf , now.Max=now.lval=now.rval=0;
		int x,y,val; scanf("%d%d%d",&x,&y,&val);
		int Lca=lca(x,y); ans = 0;
		Q1(x,Lca);
		Q2(y,Lca); printf("%lld\n",ans);
		Update(x,y,val); now.Min=inf , now.Max=now.lval=now.rval=0;
	}return 0; 
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/84727534