HDU 5770 Treasure

Description

?? has got a treasure map,the treasure map consists of N nodes,there are N-1 bidirectional roads, Each of them connects a pair of nodes,the N nodes are all connected by the N-1 bidirectional roads.?? can travel through the roads.
There are M treasures in some node. Each treasure has a value, treasures are put into boxs,each treasure corresponds to a box and each box corresponds to a key which is also in some node. Now ?? wants to plan a simple path, the path’s start point is node A,and the path’s destination is node B,?? will go from node A to node B. When ?? goes through a node(including node A and node B), he must first collects all keys, and then must open the boxes he can open in this node. The keys he got never disappear during the travel. Now ?? wants to know the maximum value he could get if he plan a best path.Can you help him?

Solution

坑走我一个早上和一个下午。。
于是我敲出了人生最长代码,打破了维修数列的记录。。

这题还是蛮牛逼的,orz现场A掉的THU大神们

我们数形结合地考虑这题
先处理出dfs序
又两点确定一条路径,那么我们可以用两个dfs序来映射一条路径
然后对于每个宝藏我们可以坐标系上的矩形来表示可以得到这个宝藏的路径
细节非常繁琐,但是不难推导,直接复制题解

假设钥匙在节点A,宝箱在节点B, C=LCA(A,B) ,则可以分四种情况讨论

1. CA,CB

对于这种情况,只要起点在以A为根的子树中,终点在以B为根的子树中,都可以拿到这份宝藏,而子树A中的所有节点dfs序连续,子树B同理,于是我们可以用一个矩阵表示能取得该宝藏的所有方案。

2. C=A,AB

对于这种情况,需要先求出节点D,D为路径(A,B)上最靠近A的节点,那么只要终点在子树B上,起点不在子树D上的路径,都可以拿到这份宝藏,而不在子树D上的点,可以用一个或者两个dfs序区间表示,因此可以用最多两个矩阵表示能取得该宝藏的所有方案。

3. C=B,AB

和情况2类似。

4. A=B

对于这种情况,若要求出所有经过节点A的路径,矩阵数目会是 n2 级别的,因此反过来思考,求出所有不包含节点A的路径,对于全部这种情况来说这样矩阵数目的级别为 n <script type="math/tex" id="MathJax-Element-7">n</script>。可以对答案先累加宝藏权值,然后对于所有不经过该点的矩阵减去这部分权值即可。

然后我们就得到了一坨矩形,用扫描线套个线段树即可求得最大值

其实还是不太难的
这个形数形结合结合还是很有借鉴意义的。。

Code(代码我缩过了)

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> vec;
typedef pair<int,int> pii;
typedef vector<pii> vecp;
#define pb push_back
#define ph push
#define fi first
#define se second
const int INF=(unsigned)-1>>1;
const ll inf=1ll<<62;
template<class T>void rd(T &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(48+x%10);
}
template<class T>void pt(T x){
    if(!x)putchar('0');
    else nt(x);
}
template<class T>void Max(T &a,T b){
    if(a<b)a=b;
}
template<class T>void Min(T &a,T b){
    if(a==-1||a>b)a=b;
}
const int M=1e5+5;
struct Edge{int to,nxt;}G[M<<1];
int head[M],tot_edge;
inline void add_edge(int from,int to){
    G[tot_edge]=(Edge){to,head[from]};
    head[from]=tot_edge++;
}
int dfn[M],f[M][20],dfs_clock,dft[M],n,m,d[M],_;
inline void up(int &u,int x){
    for(int i=0;i<20;++i)
        if(x&1<<i)u=f[u][i];
}
inline int lca(int u,int v){
    if(d[u]<d[v])swap(u,v);
    up(u,d[u]-d[v]);
    if(u==v)return u;
    for(int i=19;~i;--i)
        if(f[u][i]^f[v][i])u=f[u][i],v=f[v][i];
    return f[u][0];
}
inline void dfs(int v,int fa){
    dfn[v]=++dfs_clock;
    f[v][0]=fa,d[v]=d[fa]+1;
    for(int i=head[v];~i;i=G[i].nxt){
        int to=G[i].to;
        if(to==fa)continue;
        dfs(to,v);
    }
    dft[v]=dfs_clock;
}
inline void pret(){
    for(int j=1;j<20;++j)
        for(int i=1;i<=n;++i)
            f[i][j]=f[f[i][j-1]][j-1];
}
struct Segment_Tree{
    struct node{
        int l,r,mx,add;
    }tree[M<<2];
    inline void up(int &p){
        tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);
    }
    inline void down(int &p){
        if(!tree[p].add)return;
        tree[p<<1].add+=tree[p].add;
        tree[p<<1|1].add+=tree[p].add;
        tree[p<<1].mx+=tree[p].add;
        tree[p<<1|1].mx+=tree[p].add;
        tree[p].add=0;
    }
    void build(int l=1,int r=n,int p=1){
        tree[p]=(node){l,r,0,0};
        if(l==r)return;
        int mid=l+r>>1;
        build(l,mid,p<<1);
        build(mid+1,r,p<<1|1);
    }
    void update(int l,int r,const int x,const int flag,int p){
        if(tree[p].l==l&&tree[p].r==r){
            tree[p].add+=x*flag;
            tree[p].mx+=x*flag;
            return;
        }
        down(p);
        int mid=tree[p].l+tree[p].r>>1;
        if(r<=mid)update(l,r,x,flag,p<<1);
        else if(l>mid)update(l,r,x,flag,p<<1|1);
        else update(l,mid,x,flag,p<<1),update(mid+1,r,x,flag,p<<1|1);
        up(p);
    }
    inline int query(){
        return tree[1].mx;
    }
}sgt;
struct Matrix{int l,r,v;};
vector<Matrix>MatI[M],MatT[M];
int txt;
inline void gao(){
    cin>>n>>m;
    memset(head,-1,sizeof(head));
    tot_edge=dfs_clock=0;
    for(int i=1;i<=n;++i)
        MatI[i].clear(),MatT[i].clear();
    for(int i=1,a,b;i<n;++i){
        rd(a),rd(b);
        add_edge(a,b),add_edge(b,a);
    }
    dfs(1,1);
    pret(),sgt.build();
    int res=0,ans=-INF;
    for(int i=1,a,b,v;i<=m;++i){
        rd(a),rd(b),scanf("%d",&v);
        int w=lca(a,b);
        if(a==b){
            res+=v,v=-v;
            int l=dfn[a],r=dft[a];
            if(l-1>=1){
                MatI[1].pb((Matrix){1,l-1,v});
                MatT[l-1].pb((Matrix){1,l-1,v});
            }
            if(r+1<=n){
                MatI[r+1].pb((Matrix){r+1,n,v});
                MatT[n].pb((Matrix){r+1,n,v});
            }
            if(l-1>=1&&r+1<=n){
                MatI[1].pb((Matrix){r+1,n,v});
                MatT[l-1].pb((Matrix){r+1,n,v});
                MatI[r+1].pb((Matrix){1,l-1,v});
                MatT[n].pb((Matrix){1,l-1,v});
            }
            for(int i=head[a];~i;i=G[i].nxt){
                int to=G[i].to;
                if(to==f[a][0])continue;
                MatI[dfn[to]].pb((Matrix){dfn[to],dft[to],v});
                MatT[dft[to]].pb((Matrix){dfn[to],dft[to],v});
            }
            continue;
        }
        if(a==w){
            int k=b;up(k,d[b]-d[w]-1);
            if(dfn[a]>1){
                MatI[1].pb((Matrix){dfn[b],dft[b],v});
                MatT[dfn[a]-1].pb((Matrix){dfn[b],dft[b],v});
            }
            if(dft[a]<n){
                MatI[dft[a]+1].pb((Matrix){dfn[b],dft[b],v});
                MatT[n].pb((Matrix){dfn[b],dft[b],v});
            }
            if(dfn[a]<dfn[k]){
                MatI[dfn[a]].pb((Matrix){dfn[b],dft[b],v});
                MatT[dfn[k]-1].pb((Matrix){dfn[b],dft[b],v});
            }
            if(dft[a]>dft[k]){
                MatI[dft[k]+1].pb((Matrix){dfn[b],dft[b],v});
                MatT[dft[a]].pb((Matrix){dfn[b],dft[b],v});
            }
            continue;
        }
        if(b==w){
            int k=a;up(k,d[a]-d[w]-1);
            int l=dfn[a],r=dft[a];
            if(dfn[b]>1){
                MatI[l].pb((Matrix){1,dfn[b]-1,v});
                MatT[r].pb((Matrix){1,dfn[b]-1,v});
            }
            if(dft[b]<n){
                MatI[l].pb((Matrix){dft[b]+1,n,v});
                MatT[r].pb((Matrix){dft[b]+1,n,v});
            }
            MatI[l].pb((Matrix){dfn[b],dfn[k]-1,v});
            MatT[r].pb((Matrix){dfn[b],dfn[k]-1,v});
            if(dft[k]<dft[b]){
                MatI[l].pb((Matrix){dft[k]+1,dft[b],v});
                MatT[r].pb((Matrix){dft[k]+1,dft[b],v});
            }
            continue;
        }
        int l=dfn[a],r=dft[a];
        MatI[l].pb((Matrix){dfn[b],dft[b],v});
        MatT[r].pb((Matrix){dfn[b],dft[b],v});
    }
    for(int i=1;i<=n;++i){
        for(int j=0;j<MatI[i].size();++j){
            Matrix v=MatI[i][j];
            sgt.update(v.l,v.r,v.v,1,1);
        }
        Max(ans,res+sgt.query());
        for(int j=0;j<MatT[i].size();++j){
            Matrix v=MatT[i][j];
            sgt.update(v.l,v.r,v.v,-1,1);
        }
    }
    printf("Case #%d: ",++txt);
    cout<<ans<<endl;
}
int main(){
    for(cin>>_;_--;)gao();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值