【[TJOI2015]旅游】树剖+路径最大差值

Intersting!

传送门:https://www.luogu.org/problemnew/show/P3976

原本如果这只是 一道线段树题还是 十分简单的。对于一个区间,其路径最大差值为其max:右儿子最大差值,左儿子最大差值,右儿子MAX-左儿子MIN(或者左儿子MAX-右儿子MIN),对于这样的要返回多权值的问题,线段树传递结构体比较容易。想要做的可以转向--》水果姐系列。

但是这道题是在一个普通的树上进行的,我们就很容易想到用树链剖分来解决这个问题了。注意到要解决好一个方向怎么把控的问题。因为我们在树剖一步一步一步往上爬的时候,从询问起点往上爬和询问终点往上爬是不一样的。我的处理方式是每次都进行判断是线段树左到右还是右到左扫最大差值,之后将每段区间内的min和max记录下来(分别开两个数组从起点爬的和终点爬的),之后再将这一大段区间的min和max连接成一条链,直接暴力跑一次区间最大差值,得到最大答案就是了。

说得容易真的写得很恶心啊!!!

talk is cheap , show the code:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ls (p<<1)
#define rs (p<<1|1)
#define midd ((l+r)>>1)
using namespace std;
const int maxn=(int)5e5+5;
int n;
int fa[maxn];
int owo,la[maxn],nt[maxn],en[maxn];
inline void addedge(int a,int b)
{
    en[++owo]=b; nt[owo]=la[a]; la[a]=owo;
}
int oldid[maxn],dep[maxn],top[maxn],newid[maxn],idcnt,siz[maxn],zerz[maxn],oldp[maxn];
void fzb(int x,int ba)
{
    dep[x]=dep[ba]+1; fa[x]=ba;
    int maxsize=0; zerz[x]=0; siz[x]=1;
    for(int it=la[x];it;it=nt[it])
    {
        if(en[it]==ba) continue;
        fzb(en[it],x);
        siz[x]+=siz[en[it]];
        if(siz[en[it]]>maxsize)
        {
            maxsize=siz[en[it]];
            zerz[x]=en[it];
        }
    }
}
void lzb(int x,int ace)
{
    top[x]=ace; newid[x]=++idcnt; oldid[idcnt]=x;
    if(zerz[x]) lzb(zerz[x],ace);
    for(int it=la[x];it;it=nt[it])
    {
        if(en[it]==zerz[x]||en[it]==fa[x]) continue;
        lzb(en[it],en[it]);
    }
}
struct node
{
    int minn,maxx,ltormax,rtolmax,lazy;
}z[maxn<<3];
inline void putup(int p)
{
    z[p].maxx = max( z[ls].maxx , z[rs].maxx );
    z[p].minn = min( z[ls].minn , z[rs].minn );
    z[p].ltormax = max( z[ls].ltormax , max( z[rs].ltormax , z[rs].maxx - z[ls].minn ) );
    z[p].rtolmax = max( z[ls].rtolmax , max( z[rs].rtolmax , z[ls].maxx - z[rs].minn ) );
}
inline void putdowm(int p,int l,int r)
{
    if(l==r) { z[p].lazy=0; return; }
    z[ls].lazy +=z[p].lazy; z[rs].lazy+=z[p].lazy;
    z[ls].maxx += z[p].lazy ; z[ls].minn +=z[p].lazy ;
    z[rs].maxx += z[p].lazy ; z[rs].minn +=z[p].lazy ;
    z[p].lazy = 0; 
}
node query(int p,int l,int r,int x,int y,int mark)
{
    if(x<=l&&r<=y) 
    {
        return z[p];
    }
    if(z[p].lazy) putdowm(p,l,r);
    if(x>=midd+1)
    {
        return query(rs,midd+1,r,x,y,mark);
    }
    else if(y<=midd)
    {
        return query(ls,l,midd,x,y,mark);
    }
    node lll=query(ls,l,midd,x,y,mark);
    node rrr=query(rs,midd+1,r,x,y,mark);
    node aha;
    if(mark==1)
    {
        aha.rtolmax=max(lll.rtolmax,max(rrr.rtolmax,lll.maxx-rrr.minn));
        aha.maxx=max(lll.maxx,rrr.maxx);
        aha.minn=min(lll.minn,rrr.minn);
    }
    else 
    {
        aha.ltormax=max(lll.ltormax,max(rrr.ltormax,rrr.maxx-lll.minn));
        aha.maxx=max(lll.maxx,rrr.maxx);
        aha.minn=min(lll.minn,rrr.minn);
    }
    return aha;
}
int  xl[maxn],xr[maxn],yl[maxn],yr[maxn];
int qqq(int x,int y)
{
    int cntx=0,cnty=0; int ans=0;
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]])
        {
            node aha=query(1,1,n,newid[top[x]],newid[x],1);
            ans=max(ans,aha.rtolmax);
            xl[++cntx]=aha.minn; xr[cntx]=aha.maxx;
            x=fa[top[x]];
        }
        else
        {
            node aha=query(1,1,n,newid[top[y]],newid[y],2);
            ans=max(ans,aha.ltormax);
            yl[++cnty]=aha.minn; yr[cnty]=aha.maxx;
            y=fa[top[y]];
        }
    }
    if(dep[x]>dep[y])
    {
        node  aha=query(1,1,n,newid[y],newid[x],1);
        xl[++cntx]=aha.minn; xr[cntx]=aha.maxx;
        ans=max(ans,aha.rtolmax);
    }
    else
    {
        node aha=query(1,1,n,newid[x],newid[y],2);
        yl[++cnty]=aha.minn; yr[cnty]=aha.maxx;
        ans=max(ans,aha.ltormax);
    }
    for(int i=cnty;i>=1;i--)
    {
        xl[++cntx]=yl[i]; xr[cntx]=yr[i];//这里将他们连接成一条链子
    }
    int minn=0x3f3f3f3f;
    for(int i=1;i<=cntx;i++)
    {
        ans=max(ans,xr[i]-minn);
        minn=min(minn,xl[i]);
    }
    int maxx=-0x3f3f3f3f;
    for(int i=cntx;i>=1;i--)
    {
        ans=max(ans,maxx-xl[i]);
        maxx=max(maxx,xr[i]); 
    }//暴力跑最大差值
    if(ans<0) return 0; 
    return ans;
}
void maketree(int p,int l,int r)
{
    if(l<r)
    {
        maketree(ls,l,midd);
        maketree(rs,midd+1,r);
        putup(p);
    }
    else
    {
        z[p].minn = z[p].maxx =  oldp[ oldid[l] ]; 
        z[p].ltormax = z[p].rtolmax = z[p].lazy =0;
    }
}
void change(int p,int l,int r,int x,int y,int cc)
{
    if( x<=l&&r<=y ) { z[p].maxx+=cc; z[p].minn+=cc; z[p].lazy+=cc; return; }
    if(z[p].lazy) putdowm(p,l,r);
    if(x<=midd&&y>=l) change(ls,l,midd,x,y,cc);
    if(x<=r&&y>=midd+1) change(rs,midd+1,r,x,y,cc);
    putup(p);
}
void ccc(int a,int b,int c)
{
    while(top[a]!=top[b])
    {
        if(dep[top[a]]<dep[top[b]]) swap(a,b);
        change(1,1,n,newid[top[a]],newid[a],c);
        a=fa[top[a]];
    }
    if(dep[a]>dep[b]) swap(a,b);
    change(1,1,n,newid[a],newid[b],c);
}
void ts(int p,int l,int r)
{
    if(z[p].lazy) putdowm(p,l,r);
    if(l<r)
    {
        ts(ls,l,midd);
        ts(rs,midd+1,r);
    }
    else cout<<z[p].maxx<<' ';
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&oldp[i]);
    int a,b,c;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        addedge(a,b); addedge(b,a);
    }
    fzb(1,0); lzb(1,1); maketree(1,1,n);
    int q; scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d%d",&a,&b,&c);
        printf("%d\n",qqq(a,b));
        ccc(a,b,c);
//        ts(1,1,n); putchar(10);
    }
} 

 

posted @ 2018-03-26 23:46  Newuser233  阅读(7)  评论(0)    收藏  举报