bzoj:3999 [TJOI2015]旅游(树链剖分)

题解

bzoj3999
这题..唉..是道树剖啊
唉有方向啊~唉麻烦啊~
对于x到y的一条路径,必须是后面的最大值减前面的最小值
而树剖会把这一段分开呀
因此,每次向上跳的时候,不能只记录最大值(右子数最大-左子数组小)了,还要记录这一段的最大最小
而且而且,树剖建树是按dfn序建的树,所以,x向上跳的的部分都是反的,因此,我们还要记录反过来的最大值(左子数最大-右子数最小)
然后..因为x->top[x]在树中相当于top[x]->x,所以跳到同一条链后,x->top[x]一段的最大值,应当是反过来的最大值
同理,跳到同一条链以后,也要注意翻转啊转啊转


代码

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 50010
#define inf 0x7fffffff
struct node{int x,y,next;}mp[2*N];
int n,m,num=0,tot=0,d[N],size[N],son[N],fa[N],h[N],top[N],id[N],real[N],a[N];
struct node1{
    int l,r,mx,mn,ans,ans1,f;
    node1(){ans=mx=ans1=f=0,mn=inf;} 
}tree[4*N];
void insert(int x,int y){
    mp[++num].x=x;mp[num].y=y;mp[num].next=h[x];h[x]=num;
    mp[++num].x=y;mp[num].y=x;mp[num].next=h[y];h[y]=num;
}
void dfs1(int u){
    size[u]=1;
    for(int i=h[u];i;i=mp[i].next){
        int v=mp[i].y;
        if(!d[v]){
            fa[v]=u;d[v]=d[u]+1;
            dfs1(v);size[u]+=size[v];
            if(size[son[u]]<size[v]) son[u]=v;
        }
    }
}
void dfs2(int u,int tp){
    top[u]=tp;id[u]=++tot;real[tot]=u;
    if(son[u]) dfs2(son[u],tp);
    for(int i=h[u];i;i=mp[i].next){
        int v=mp[i].y;
        if(v!=son[u] && d[v]==d[u]+1) dfs2(v,v);
    }
}
void update(int v){
    tree[v].mx=max(tree[v<<1].mx,tree[v<<1|1].mx);
    tree[v].mn=min(tree[v<<1].mn,tree[v<<1|1].mn);
    tree[v].ans=max(tree[v<<1|1].mx-tree[v<<1].mn,max(tree[v<<1].ans,tree[v<<1|1].ans));
    tree[v].ans1=max(tree[v<<1].mx-tree[v<<1|1].mn,max(tree[v<<1].ans1,tree[v<<1|1].ans1));
}
void build(int v,int l,int r){
    tree[v].l=l;tree[v].r=r;
    if(l==r){
        tree[v].ans=tree[v].ans1=tree[v].f=0;tree[v].mx=tree[v].mn=a[real[l]];
        return ;
    }int mid=l+r>>1;
    build(v<<1,l,mid);build(v<<1|1,mid+1,r);
    update(v);
}
void pushdown(int v){
    if(!tree[v].f) return;
    tree[v<<1].f+=tree[v].f;tree[v<<1|1].f+=tree[v].f;
    tree[v<<1].mx+=tree[v].f;tree[v<<1|1].mx+=tree[v].f;
    tree[v<<1].mn+=tree[v].f;tree[v<<1|1].mn+=tree[v].f;
    tree[v].f=0;
}
node1 update1(node1 x,node1 y){
    node1 z;
    z.ans=max(y.mx-x.mn,max(x.ans,y.ans));
    z.ans1=max(x.mx-y.mn,max(x.ans1,y.ans1));
    z.mn=min(x.mn,y.mn);z.mx=max(x.mx,y.mx);
    return z; 
}
node1 query(int v,int l,int r,int x){
    if(l<=tree[v].l && tree[v].r<=r){
        tree[v].f+=x;tree[v].mx+=x;tree[v].mn+=x;
        return tree[v];
    }int mid=tree[v].l+tree[v].r>>1;node1 s1,s2;pushdown(v);
    if(l<=mid) s1=query(v<<1,l,r,x);
    if(mid<r) s2=query(v<<1|1,l,r,x);
    update(v);return update1(s1,s2);
}
int solve(int x,int y,int z){
    node1 ansl,ansr,ans;
    while(top[x]!=top[y]){
        if(d[top[x]]>=d[top[y]]){
            ansl=update1(query(1,id[top[x]],id[x],z),ansl);
            x=fa[top[x]];
        }else{
            ansr=update1(query(1,id[top[y]],id[y],z),ansr);
            y=fa[top[y]];
        }
    }swap(ansl.ans,ansl.ans1);
    if(id[x]<=id[y]) ansl=update1(ansl,query(1,id[x],id[y],z));
    else{
        node1 t=query(1,id[y],id[x],z);swap(t.ans,t.ans1);
        ansr=update1(t,ansr);
    }ans=update1(ansl,ansr);
    return ans.ans;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<n;i++){
        int x,y;scanf("%d%d",&x,&y);
        insert(x,y);
    }d[1]=1;dfs1(1);dfs2(1,1);
    build(1,1,n);scanf("%d",&m);
    for(int i=1;i<=m;i++){
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        printf("%d\n",solve(x,y,z));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunshiness_s/article/details/79720711