P9704 「TFOI R1」Tree Home 题解

题目传送门

思路

首先我们需要依据输入来建立一棵树并将 \(d\) 数组求出来,此操作我们可以用链式前向星来存树,然后 dfs 算出 \(d\) 数组。

接着我们需要把题目上给我们的式子推出来:

\[\operatorname{f}\left(a, b, c \right) = \left(a - b \right)\left[a^2 + b^2 + a \times b + 3 \times c \times \left(a + b + c\right)\right] \]

\[\operatorname{f}\left( d_p - d_r,d_q - d_r ,d_r\right) \]

\[= \left( d_p - d_q \right)\left[ {d_p}^2 - 2d_p\times d_r +{d_r}^2 + {d_q}^2 - 2d_q\times d_r +{d_r}^2 + d_p\times d_q - d_p\times d_r -d_q\times d_r + {d_r}^2 +3d_r\left( d_p + d_q - d_r \right)\right] \]

\[= {d_p}^3-{d_q}^3 \]

所以题中询问的式子:

\[|\operatorname{f}(d_{p} - d_{r}, d_{q} - d_{r}, d_{r})| + |v_{p} - v_{q}| = |{d_p}^3 - {d_q}^3| + |v_{p} - v_{q}| \]

这样就化到最简了。此时我们需要把绝对值拆开,有四种情况:

  1. \(v_p \ge v_q\)\({d_p}^3 \ge {d_q}^3\),那么式子就是 \({d_p}^3 - {d_q}^3 + v_p - v_q\)

  2. \(v_p \ge v_q\)\({d_p}^3 < {d_q}^3\),那么式子就是 \({d_q}^3 - {d_p}^3 + v_p - v_q\)

  3. \(v_p < v_q\)\({d_p}^3 \ge {d_q}^3\),那么式子就是 \({d_p}^3 - {d_q}^3 + v_q - v_p\)

  4. \(v_p < v_q\)\({d_p}^3 < {d_q}^3\),那么式子就是 \({d_q}^3 - {d_p}^3 + v_q - v_p\)

我们再令 \(a_i = v_i + {d_i}^3\)\(b_i = v_i - {d_i}^3\),以上四种情况就可以化简为:

  1. \(a_p - a_q\)

  2. \(b_p - b_q\)

  3. \(b_q - b_p\)

  4. \(b_q - a_p\)

题目要求是让结果最大,那么就相当于我们让最大值减去最小值即能让答案最大,这里我们用两颗线段树 \(tree1\)\(tree2\) 来维护 \(a\) 序列与 \(b\) 序列的最大值和最小值,时间复杂度为 \(\mathcal{O}\left(n\ \log\ n\right)\)

代码

#include<bits/stdc++.h>
#define MAX 200005
using namespace std;
struct Tree{
    int l,r,minn,maxn;
}tree1[MAX*4],tree2[MAX*4];//两棵树
int n,T,A[MAX],cnt,head[MAX],a[MAX],b[MAX],dis[MAX],ans;
void pushup1(int k){
    tree1[k].l=tree1[k*2].l;
    tree1[k].r=tree1[k*2+1].r;
    tree1[k].minn=min(tree1[k*2].minn,tree1[k*2+1].minn);
    tree1[k].maxn=max(tree1[k*2].maxn,tree1[k*2+1].maxn);
}
void pushup2(int k){
    tree2[k].l=tree2[k*2].l;
    tree2[k].r=tree2[k*2+1].r;
    tree2[k].minn=min(tree2[k*2].minn,tree2[k*2+1].minn);
    tree2[k].maxn=max(tree2[k*2].maxn,tree2[k*2+1].maxn);
}
void build1(int k,int l,int r){//第一棵树,用来存a数组
    tree1[k].l=l,tree1[k].r=r;
    if(l==r){
        tree1[k].minn=tree1[k].maxn=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build1(k*2,l,mid);
    build1(k*2+1,mid+1,r);
    pushup1(k);
}
void build2(int k,int l,int r){//第二棵树,用来存b数组
    tree2[k].l=l,tree2[k].r=r;
    if(l==r){
        tree2[k].minn=tree2[k].maxn=b[l];
        return;
    }
    int mid=(l+r)>>1;
    build2(k*2,l,mid);
    build2(k*2+1,mid+1,r);
    pushup2(k);
}
Tree merge(Tree Left,Tree Right){
    Tree x;
    x.l=Left.l,x.r=Right.r;
    x.minn=min(Left.minn,Right.minn);
    x.maxn=max(Left.maxn,Right.maxn);
    return x;
}
Tree query1(int k,int l,int r){
    if(tree1[k].l>=l&&tree1[k].r<=r){
        return tree1[k];
    }
    if(r<=tree1[k*2].r)return query1(k*2,l,r);
    if(l>=tree1[k*2+1].l)return query1(k*2+1,l,r);
    return merge(query1(k*2,l,r),query1(k*2+1,l,r));
}
Tree query2(int k,int l,int r){
    if(tree2[k].l>=l&&tree2[k].r<=r){
        return tree2[k];
    }
    if(r<=tree2[k*2].r)return query2(k*2,l,r);
    if(l>=tree2[k*2+1].l)return query2(k*2+1,l,r);
    return merge(query2(k*2,l,r),query2(k*2+1,l,r));
}
struct Edge{
    int to,next,val;
}edge[MAX*2];
void add(int u,int v,int w){//链式前向星
    edge[++cnt].to=v;
    edge[cnt].val=w;
    edge[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int x,int fa){//深搜
    for(int i=head[x];i;i=edge[i].next){
        int v=edge[i].to,w=edge[i].val;
        if(v==fa)continue;
        dis[v]=dis[x]+w;
        dfs(v,x);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>T;
    for(int i=1;i<=n;i++){
        cin>>A[i];
    }
    int u,v,w,l1,r1,l2,r2;
    for(int i=1;i<=n-1;i++){
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    dfs(1,0);
    for(int i=1;i<=n;i++){
        a[i]=A[i]+(dis[i]*dis[i]*dis[i]);
        b[i]=A[i]-(dis[i]*dis[i]*dis[i]);
    }
    build1(1,1,n);
    build2(1,1,n);
    while(T--){
        cin>>l1>>r1>>l2>>r2;
        ans=0;
        Tree a1=query1(1,l1,r1),a2=query1(1,l2,r2),b1=query2(1,l1,r1),b2=query2(1,l2,r2);
        ans=max({ans,a1.maxn-a2.minn,a2.maxn-a1.minn,b1.maxn-b2.minn,b2.maxn-b1.minn});//四种情况
        cout<<ans<<'\n';
    }
    return 0;
}
posted @ 2024-01-20 11:53  GyrthCurunír  阅读(7)  评论(0编辑  收藏  举报