zoukankan      html  css  js  c++  java
  • HDU 5052 /// 树链剖分+线段树区间合并

    题目大意:

    给定n (表示树有n个结点)

    接下来n行给定n个点的点权(在这个点上买鸡或者卖鸡的价钱就是点权)

    接下来n-1行每行给定 x y 表示x结点和y结点之间有一条边

    给定q (表示有q个询问)

    接下来q行 每行给定 x y v

    查询x到y的路径上 先买鸡再卖鸡能够赢得的最大利润

    买卖完后 x到y整条路径的点权都要加上v

    因为必须先买再卖 所以这个买卖有方向性

    就得维护区间 从左向右买卖的最大利润maxl 和 从右向左买卖的最大利润maxr

    而 从左向右买卖的利润maxl = 右子区间的最大值 - 左子区间的最小值 (maxr同理)

    所以还要维护区间 最大值maxw 和 最小值minw

    整条路径都加上v 区间更新还要加个 lazy 标记

    查询时 最后路径被分成 LCA-x 和 LCA-y 由LCA到底部的两段 

    所以按方向更新答案应该 ans=max( LCA-y.maxl , LCA-x.maxr )

    最后还要通过 ans=max( ans , LCA-y.maxw - LCA-x.minw ) 更新一下答案

    最后 我的代码里 线段树的 pushUp() 操作直接调用了 Merge() 函数

    而 lazy 在合并前已经更新过了 防止出错 将已得到的 lazy 传参赋值

    而查询时的合并操作 只需要查询线段树 不需要修改 所以lazy直接传个没用的0就好了

    #include <stdio.h>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define mem(i,j) memset(i,j,sizeof(i))
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define root 1,n,1
    
    const int maxn=1e5+5;
    int n, q, w[maxn];
    
    struct IntervalTree {
        struct EDGE { int to,ne; }e[maxn<<1];
        int head[maxn], tot;
        void addE(int u,int v) {
            e[tot].to=v;
            e[tot].ne=head[u];
            head[u]=tot++;
        }
    
        int fa[maxn], son[maxn], dep[maxn], num[maxn];
        int top[maxn], p[maxn], fp[maxn], pos;
    
        void init() {
            tot=1; mem(head,0);
            pos=0; mem(son,0);
        }
    
        struct TREE {
            int lazy;
            int maxw,minw; // 区间极值
            int maxl,maxr; // 从左开始最大差值 从右开始最大差值
            TREE(){ lazy=maxw=minw=maxl=maxr=0; }
        }tree[maxn<<2];
    
    // --------------------以下是线段树-------------------------
    
        TREE Merge(TREE L,TREE R,int lazy) {
            if(R.maxw==0) return L;
            TREE ans; ans.lazy=lazy;
            ans.maxw=max(L.maxw,R.maxw);
            ans.minw=min(L.minw,R.minw);
            ans.maxl=max(max(L.maxl,R.maxl),R.maxw-L.minw);
            ans.maxr=max(max(L.maxr,R.maxr),L.maxw-R.minw);
            return ans;
        }
        void pushUp(int rt) {
            tree[rt]=Merge(tree[rt<<1],tree[rt<<1|1],tree[rt].lazy);
        }
        void pushDown(int rt) {
            if(tree[rt].lazy) {
                int t=tree[rt].lazy;
                tree[rt<<1].minw+=t;
                tree[rt<<1].maxw+=t;
                tree[rt<<1].lazy+=t;
                tree[rt<<1|1].minw+=t;
                tree[rt<<1|1].maxw+=t;
                tree[rt<<1|1].lazy+=t;
                tree[rt].lazy=0;
            } // 差值不变 不需要更新
        }
        void build(int l,int r,int rt) {
            tree[rt].lazy=0;
            if(l==r) {
                tree[rt].maxw=tree[rt].minw=fp[l];
                tree[rt].maxl=tree[rt].maxr=0;
                return;
            }
            int m=(l+r)>>1;
            build(lson), build(rson);
            pushUp(rt);
        }
        void update(int L,int R,int v,int l,int r,int rt) {
            if(l==L && R==r) {
                tree[rt].lazy+=v;
                tree[rt].maxw+=v;
                tree[rt].minw+=v;
                return;
            }
            pushDown(rt);
            int m=(l+r)>>1;
            if(R<=m) update(L,R,v,lson);
            else if(L>m) update(L,R,v,rson);
            else update(L,m,v,lson),update(m+1,R,v,rson);
            pushUp(rt);
        }
        TREE query(int L,int R,int l,int r,int rt) {
            if(L==l && r==R) return tree[rt];
            pushDown(rt);
            int m=(l+r)>>1;
            if(R<=m) return query(L,R,lson);
            else if(L>m) return query(L,R,rson);
            else return Merge(query(L,m,lson),query(m+1,R,rson),tree[rt].lazy);
        }
    
    // --------------------以上是线段树-------------------------
    
    // --------------------以下是树链剖分-------------------------
    
        void dfs1(int u,int pre,int d) {
            dep[u]=d; fa[u]=pre; num[u]=1;
            for(int i=head[u];i;i=e[i].ne) {
                int v=e[i].to;
                if(v!=fa[u]) {
                    dfs1(v,u,d+1);
                    num[u]+=num[v];
                    if(!son[u] || num[v]>num[son[u]])
                        son[u]=v;
                }
            }
        }
        void dfs2(int u,int sp) {
            top[u]=sp; p[u]=++pos; fp[p[u]]=w[u];
            if(!son[u]) return;
            dfs2(son[u],sp);
            for(int i=head[u];i;i=e[i].ne) {
                int v=e[i].to;
                if(v!=son[u] && v!=fa[u])
                    dfs2(v,v);
            }
        }
        int solve(int x,int y,int v) {
            int fx=top[x], fy=top[y];
            TREE ans1, ans2;
            while(fx!=fy) {
                if(dep[fx]>dep[fy]) {
                    ans1=Merge(query(p[fx],p[x],root),ans1,0);
                    update(p[fx],p[x],v,root);
                    x=fa[fx];
                } else {
                    ans2=Merge(query(p[fy],p[y],root),ans2,0);
                    update(p[fy],p[y],v,root);
                    y=fa[fy];
                }
                fx=top[x], fy=top[y];
            }
            if(p[x]>p[y]) {
                ans1=Merge(query(p[y],p[x],root),ans1,0);
                update(p[y],p[x],v,root);
            }
            else {
                ans2=Merge(query(p[x],p[y],root),ans2,0);
                update(p[x],p[y],v,root);
            }
            int ans=max(ans1.maxr,ans2.maxl);
            if(ans1.minw) ans=max(ans,ans2.maxw-ans1.minw);
            return ans;
        }
    
    // --------------------以上是树链剖分-------------------------
    
        void initQTree() {
            dfs1(1,0,0), dfs2(1,1);
            build(root);
        }
    }T;
    
    int main()
    {
        int t; scanf("%d",&t);
        while(t--) {
            scanf("%d",&n);
            T.init();
            for(int i=1;i<=n;i++) scanf("%d",&w[i]);
            for(int i=2;i<=n;i++) {
                int u,v; scanf("%d%d",&u,&v);
                T.addE(u,v); T.addE(v,u);
            }
            T.initQTree();
            scanf("%d",&q);
            while(q--) {
                int x,y,v; scanf("%d%d%d",&x,&y,&v);
                printf("%d
    ",T.solve(x,y,v));
            }
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    VS2012 professional和VS2012 Ultimate的区别
    ConcurrentDictionary和Dictionary
    ConcurrentDictionary的ToDictionary
    AutoResetEvent
    查看局域网内某个ip的mac地址
    斗争程序猿(三十八)——历史朝代大学(两)——我与数据库的故事
    Windowsport80解决方案被占用
    unity3d 各功能的运行秩序,打回来,订购,的次数
    蜘蛛爱上你的网站
    Java线(一个):线程安全的和不安全
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10010443.html
Copyright © 2011-2022 走看看