zoukankan      html  css  js  c++  java
  • 题解 洛谷 P4695 【[PA2017]Banany】

    考虑用动态点分治来解决像本题这样带修的树上路径问题。

    首先对原树进行点分治,建出点分树,在点分树每个节点上用动态开点线段树来维护以该节点为起点,到其点分树子树中每个节点的利润。

    查询时只需在点分树上当前所在节点往上跳父亲,在其到点分树根节点的链上的每个节点的线段树上查询。跳到一个节点时,在线段树上查询除了当前节点的利润最大值,同时加上其到当前节点的花费。

    修改点权只需在点分树上往上跳父亲,在线段树上单点修改即可。

    考虑边权的修改影响的是当前根所对应的一个子树,对于边权的修改,从其两个端点在点分树上深度更大,即点分治递归层数更深的点开始往上跳父亲,每次修改在原树上以当前节点为根,深度更浅的那个端点。

    点分树上每个节点的线段树在维护时以节点的 (dfs) 序为下标,修改子树信息只需在线段树上区间修改即可。

    (code:)

    #include<bits/stdc++.h>
    #define maxn 100010
    #define maxm 200010
    #define maxt 3500010
    #define inf 1000000000000000
    #define mid ((l+r)>>1)
    #define mk make_pair
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,q,tree_cnt,dfn_cnt,tot,root,pos=1;
    int fa[maxn],ma[maxn],siz[maxn],num[maxn],d[maxn];
    int rt[maxn],ls[maxt],rs[maxt],in[20][maxn],out[20][maxn];
    ll v[maxn],tag[maxt];
    bool vis[maxn];
    map<pair<int,int>,ll> w;
    struct edge
    {
        int to,nxt;
        ll v;
    }e[maxm];
    int head[maxn],edge_cnt;
    void add(int from,int to,ll val)
    {
        e[++edge_cnt]=(edge){to,head[from],val};
        head[from]=edge_cnt;
    }
    struct node
    {
        ll val;
        int id;
    }t[maxt];
    bool operator <(const node &a,const node &b)
    {
        if(a.val==b.val) return a.id>b.id;
        return a.val<b.val;
    }
    void pushtag(int cur,ll v)
    {
        t[cur].val+=v,tag[cur]=v;
    }
    void pushdown(int cur)
    {
        if(!tag[cur]) return;
        pushtag(ls[cur],tag[cur]),pushtag(rs[cur],tag[cur]),tag[cur]=0;
    }
    void insert(int l,int r,int pos,ll v,int id,int &cur)
    {
        if(!cur) cur=++tree_cnt;
        if(l==r)
        {
            t[cur]=(node){v,id};
            return;
        }
        if(pos<=mid) insert(l,mid,pos,v,id,ls[cur]);
        else insert(mid+1,r,pos,v,id,rs[cur]);
        t[cur]=max(t[ls[cur]],t[rs[cur]]);
    }
    void modify(int L,int R,int l,int r,ll v,int &cur)
    {
        if(!cur) cur=++tree_cnt;
        if(L<=l&&R>=r)
        {
            pushtag(cur,v);
            return;
        }
        pushdown(cur);
        if(L<=mid) modify(L,R,l,mid,v,ls[cur]);
        if(R>mid) modify(L,R,mid+1,r,v,rs[cur]);
        t[cur]=max(t[ls[cur]],t[rs[cur]]);
    }
    node query(int L,int R,int l,int r,int cur)
    {
        if(L>R||!cur) return (node){-inf,0};
        if(L<=l&&R>=r) return t[cur];
        pushdown(cur);
        if(R<=mid) return query(L,R,l,mid,ls[cur]);
        if(L>mid) return query(L,R,mid+1,r,rs[cur]);
        return max(query(L,R,l,mid,ls[cur]),query(L,R,mid+1,r,rs[cur]));
    }
    void dfs_root(int x,int fath)
    {
        siz[x]=1,ma[x]=0;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(vis[y]||y==fath) continue;
            dfs_root(y,x),siz[x]+=siz[y],ma[x]=max(ma[x],siz[y]);
        }
        ma[x]=max(ma[x],tot-siz[x]);
        if(ma[x]<ma[root]) root=x;
    }
    void dfs_dis(int x,int fath,ll dis,int id)
    {
        in[d[id]][x]=++dfn_cnt,insert(1,num[id],dfn_cnt,v[x]-dis,x,rt[id]);
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(vis[y]||y==fath) continue;
            dfs_dis(y,x,dis+e[i].v,id);
        }
        out[d[id]][x]=dfn_cnt;
    }
    void solve(int x,int depth)
    {
        int now=tot;
        d[x]=depth,vis[x]=true,num[x]=now,dfn_cnt=0,dfs_dis(x,0,0,x);
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(vis[y]) continue;
            root=0,tot=siz[y];
            if(siz[y]>siz[x]) tot=now-siz[x];
            dfs_root(y,x),fa[root]=x,solve(root,depth+1);
        }
    }
    int main()
    {
        read(n),read(q);
        for(int i=1;i<=n;++i) read(v[i]);
        for(int i=1;i<n;++i)
        {
            int x,y;
            ll v;
            read(x),read(y),read(v);
            add(x,y,v),add(y,x,v);
            if(x>y) swap(x,y);
            w[mk(x,y)]=v;
        }
        tot=ma[0]=n,dfs_root(1,0),solve(root,1);
        while(q--)
        {
            int opt,x,y,p;
            ll val,t;
            node ans=(node){-inf,0};
            read(opt);
            if(opt==1)
            {
                read(x),read(val);
                for(int i=x;i;i=fa[i])
                    modify(in[d[i]][x],in[d[i]][x],1,num[i],val-v[x],rt[i]);
                v[x]=val;
            }
            else
            {
                read(x),read(y),read(val);
                if(x>y) swap(x,y);
                t=w[mk(x,y)]-val,w[mk(x,y)]=val;
                if(d[x]<d[y]) p=x;
                else p=y;
                while(p)
                {
                    if(in[d[p]][x]>in[d[p]][y]) modify(in[d[p]][x],out[d[p]][x],1,num[p],t,rt[p]);
                    else modify(in[d[p]][y],out[d[p]][y],1,num[p],t,rt[p]);
                    p=fa[p];
                }
            }
            for(int i=pos;i;i=fa[i])
            {
                node now=max(query(1,in[d[i]][pos]-1,1,num[i],rt[i]),query(in[d[i]][pos]+1,num[i],1,num[i],rt[i]));
                now.val+=query(in[d[i]][pos],in[d[i]][pos],1,num[i],rt[i]).val-v[pos],ans=max(ans,now);
            }
            printf("%d ",pos=ans.id);
        }
        return 0;
    }
    
  • 相关阅读:
    HDU2647(拓扑排序+反向建图)
    Android Activity之间通信
    Swift 编程语言学习0.1——Swift简单介绍
    HDU 5012 Dice (BFS)
    当向后台插入或读取JSON数据遇见回车时
    Android CTS測试Fail项改动总结(四)
    【Unity 3D】学习笔记三十五:游戏实例——摄像机切换镜头
    android蓝牙4.0(BLE)开发之ibeacon初步
    Error opening zip file or JAR manifest missing : D:play-1.2.5/framework/play-1.2.5.jar
    Codeforces Round #256 (Div. 2)——Multiplication Table
  • 原文地址:https://www.cnblogs.com/lhm-/p/13347188.html
Copyright © 2011-2022 走看看