zoukankan      html  css  js  c++  java
  • TJOI2015 旅游

    题目链接:戳我

    树上有向信息合并。

    用树链剖分把其转化为序列上的问题——求区间中最大数-最小数的差,限制为最小数必须在最大数前面选取。

    有两种选择方法,一种是先选择全局最大数,在它前面区间中选择最小数。一种是选择全局最小数,然后在它后面的区间种选择最大的。(证明只有这两种情况——加入我们选择了一个全局次大,只有当最小数小于它前面区间最小数才有可能最优,最佳情况下会选到全局最小。但是由于它的全局次大在这个选择的最小数的后面,而这又一定不比选择全局最小+其后面的最大更优)

    对于一条链(u,v),我们需要记录四个量——最小值,最大值,u->v的最大差,v->u的最大差(记录后面这两个是因为我们不知道出发点和终点哪一个的dfn更大)

    合并后面两个量的时候注意有两种情况,一种是直接取左右儿子中的最大值(也就是左右两个区间内进行选择的最大值),一种是跨区间,需要lson.max-rson.min或者rson.max-lson.min。

    然后最后更新答案的时候不要忘了有两种选择方法哦,要分类讨论取最优qwq~

    代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define check
    #define MAXN 100010
    #define INF 1e18
    using namespace std;
    
    int n,m,tt,cnt;
    int head[MAXN],dfn[MAXN],siz[MAXN],dep[MAXN],fa[MAXN],top[MAXN],son[MAXN];
    long long p_max[MAXN],p_min[MAXN],q_min[MAXN],q_max[MAXN],w[MAXN],wt[MAXN];
    
    struct Edge{int nxt,to;}edge[MAXN<<1];
    struct Node{long long maxx,minn,d,_d,tag;}t[MAXN<<2];
    
    inline int ls(int x){return x<<1;}
    inline int rs(int x){return x<<1|1;}
    inline void add(int from,int to){edge[++tt].nxt=head[from],edge[tt].to=to,head[from]=tt;}
    
    inline void push_up(int x)
    {
        t[x].maxx=max(t[ls(x)].maxx,t[rs(x)].maxx);
        t[x].minn=min(t[ls(x)].minn,t[rs(x)].minn);
        t[x].d=max(t[ls(x)].d,t[rs(x)].d);
        t[x].d=max(t[x].d,t[rs(x)].maxx-t[ls(x)].minn);
        t[x]._d=max(t[ls(x)]._d,t[rs(x)]._d);
        t[x]._d=max(t[x]._d,t[ls(x)].maxx-t[rs(x)].minn);
    }
    
    inline void push_down(int x)
    {
        if(t[x].tag)
        {
            t[ls(x)].tag+=t[x].tag,t[ls(x)].maxx+=t[x].tag,t[ls(x)].minn+=t[x].tag;
            t[rs(x)].tag+=t[x].tag,t[rs(x)].maxx+=t[x].tag,t[rs(x)].minn+=t[x].tag;
            t[x].tag=0;
        }
    }
    
    inline void build(int x,int l,int r)
    {
        if(l==r){t[x].minn=t[x].maxx=wt[l];t[x].d=t[x]._d=0;return;}
        int mid=(l+r)>>1;
        build(ls(x),l,mid);
        build(rs(x),mid+1,r);
        push_up(x);
    }
    
    inline void update(int x,int l,int r,int ll,int rr,long long k)
    {
        if(ll<=l&&r<=rr)
        {
            t[x].maxx+=k,t[x].minn+=k,t[x].tag+=k;
            return;
        }
        int mid=(l+r)>>1;
        push_down(x);
        if(ll<=mid) update(ls(x),l,mid,ll,rr,k);
        if(mid<rr)  update(rs(x),mid+1,r,ll,rr,k);
        push_up(x);
    }
    
    inline void UPDATE(int x,int y,long long k)
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            update(1,1,n,dfn[top[x]],dfn[x],k);
            x=fa[top[x]];
        }
        if(dep[x]<dep[y]) swap(x,y);
        update(1,1,n,dfn[y],dfn[x],k);
    }
    
    inline Node query(int x,int l,int r,int ll,int rr)
    {
        if(ll<=l&&r<=rr) return t[x];
        int mid=(l+r)>>1;
        push_down(x);
        Node cur1,cur2,cur3;
        cur1.d=cur1._d=0,cur1.maxx=-INF,cur1.minn=INF;
        cur2.d=cur2._d=0,cur2.maxx=-INF,cur2.minn=INF;
        cur3.d=cur3._d=0,cur3.maxx=-INF,cur3.minn=INF;
        if(ll<=mid) cur2=query(ls(x),l,mid,ll,rr);
        if(mid<rr) cur3=query(rs(x),mid+1,r,ll,rr);
        cur1.maxx=max(cur2.maxx,cur3.maxx);
        cur1.minn=min(cur2.minn,cur3.minn);
        cur1.d=max(cur2.d,cur3.d);
        cur1._d=max(cur2._d,cur3._d);
        if(ll<=mid&&mid<rr) 
            cur1.d=max(cur1.d,cur3.maxx-cur2.minn),cur1._d=max(cur1._d,cur2.maxx-cur3.minn);
        return cur1;
    }
    
    inline long long QUERY(int x,int y)
    {
        int cnt1=0,cnt2=0;long long ans=-INF,now_min=INF,now_max=-INF;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]>dep[top[y]])
            {
                Node cur=query(1,1,n,dfn[top[x]],dfn[x]);
                ans=max(ans,cur._d);
                p_max[++cnt1]=cur.maxx,p_min[cnt1]=cur.minn;
                x=fa[top[x]];
            }
            else
            {
                Node cur=query(1,1,n,dfn[top[y]],dfn[y]);
                ans=max(ans,cur.d);
                q_max[++cnt2]=cur.maxx,q_min[cnt2]=cur.minn;
                y=fa[top[y]];
            }
        }
        if(dep[x]<dep[y])
        {
            Node cur=query(1,1,n,dfn[x],dfn[y]);
            ans=max(ans,cur.d);
            q_max[++cnt2]=cur.maxx,q_min[cnt2]=cur.minn;
        }
        else
        {
            Node cur=query(1,1,n,dfn[y],dfn[x]);
            ans=max(ans,cur._d);
            p_max[++cnt1]=cur.maxx,p_min[cnt1]=cur.minn;
        }
        for(int i=cnt2;i>=1;i--) p_max[++cnt1]=q_max[i],p_min[cnt1]=q_min[i];
        for(int i=1;i<=cnt1;i++) ans=max(ans,p_max[i]-now_min),now_min=min(now_min,p_min[i]);
        for(int i=cnt1;i>=1;i--) ans=max(ans,now_max-p_min[i]),now_max=max(now_max,p_max[i]);
        return ans;
    }
    
    inline void dfs1(int x,int pre)
    {
        fa[x]=pre;
        dep[x]=dep[pre]+1;
        siz[x]=1;
        long long maxx=-1;
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v==pre) continue;
            dfs1(v,x);
            siz[x]+=siz[v];
            if(siz[v]>maxx) maxx=siz[v],son[x]=v;
        }
    }
    
    inline void dfs2(int x,int topf)
    {
        top[x]=topf;
        dfn[x]=++cnt;
        wt[cnt]=w[x];
        if(son[x]) dfs2(son[x],topf);
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(v==fa[x]||v==son[x]) continue;
            dfs2(v,v);
        }
    }
    
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce1.in","r",stdin);
        freopen("ce.out","w",stdout);
        #endif
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v),add(v,u);
        }
        dfs1(1,1);
        dfs2(1,1);
        build(1,1,n);
        /*for(int i=1;i<=n;i++) printf("son[%d]=%d
    ",i,son[i]);puts("");
        for(int i=1;i<=n;i++) printf("top[%d]=%d
    ",i,top[i]);puts("");
        for(int i=1;i<=n;i++) printf("dfn[%d]=%d
    ",i,dfn[i]);puts("");*/
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int u,v;long long w;
            scanf("%d%d%lld",&u,&v,&w);
            printf("%lld
    ",QUERY(u,v));
            UPDATE(u,v,w);
        }
        return 0;
    }
    
  • 相关阅读:
    轮询算法
    随机算法
    加权随机算法
    平滑加权轮询算法
    预训练模型与Keras.applications.models权重资源地址
    多通道卷积操作解析
    Squeeze-and-Excitation Networks
    实验数据集概况
    Keras-图片预处理
    Keras常用层
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10361347.html
Copyright © 2011-2022 走看看