【JZOJ5248】花花的聚会

Description

Pic

注意测试数据中道路是

的单向道路,与题面恰好相反。

Input

Output

Sample Input

7 7
1 3
1 2
6 7
3 6
3 5
3 4
7 2 3
7 1 1
2 3 5
3 6 2
4 2 4
5 3 10
6 1 20
3
5
6
7

Sample Output

Pic

 

题解:

  这个题目,首先dp十分显然,设dp[i]表示强制在i这个节点购买的走到1号节点的最小话花费转移起来就可以了.

  但显然我们要求可以用这个票到达的祖先节点中dp[x]的最小值,考虑,将票按起点的dfn排序,每次用票来更新dp值,每次更新就在线段树里修改就可以了,线段树维护区间极小值.

 

代码:

  

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#define MAXN 100010
#define ll long long
using namespace std;
int n,m,q;
int fa[MAXN],dep[MAXN],dfn[MAXN],sz[MAXN],top[MAXN],son[MAXN],id[MAXN];
ll dp[MAXN];
struct edge{
    int first;
    int next;
    int to;
}a[MAXN*2];
struct piao{
    int x,ti,co;
    void read(){
        scanf("%d%d%d",&x,&ti,&co);
    }
}g[MAXN];
struct tree{
    int l,r;ll minn;
}tr[MAXN*4];
int num=0;

void addedge(int from,int to){
    a[++num].to=to;
    a[num].next=a[from].first;
    a[from].first=num;
}

void dfs1(int now,int f){
    fa[now]=f,sz[now]=1,dep[now]=dep[f]+1;
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(to==f) continue;
        dfs1(to,now);
        sz[now]+=sz[to];
        if(sz[son[now]]<sz[to]) son[now]=to;
    }
}

void dfs2(int now,int tp){
    top[now]=tp;
    dfn[now]=++num;id[dfn[now]]=now;
    if(son[now]) dfs2(son[now],tp);
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(to==fa[now]||to==son[now]) continue;
        dfs2(to,to);
    }
}

void pushup(int xv){
    tr[xv].minn=min(tr[xv*2].minn,tr[xv*2+1].minn);
}

void build(int xv,int l,int r){
    if(l==r){
        tr[xv].l=l,tr[xv].r=r;
        tr[xv].minn=1ll<<60;
        return;
    }
    tr[xv].l=l,tr[xv].r=r;int mid=(l+r)>>1;
    build(xv*2,l,mid),build(xv*2+1,mid+1,r);
    pushup(xv);
}

bool cmp(piao x,piao y){
    return dfn[x.x]<dfn[y.x];
}

void insert(int xv,int ps,int x){
    int l=tr[xv].l,r=tr[xv].r,mid=(l+r)>>1;
    if(l==r){
        tr[xv].minn=x;return;
    }
    if(ps<=mid) insert(xv*2,ps,x);else insert(xv*2+1,ps,x);
    pushup(xv);
}

ll query(int xv,int l,int r){
    int L=tr[xv].l,R=tr[xv].r,mid=(L+R)/2;
    if(l==L&&r==R) return tr[xv].minn;
    if(r<=mid) return query(xv*2,l,r);
    else if(l>mid) return query(xv*2+1,l,r);
    else return min(query(xv*2,l,mid),query(xv*2+1,mid+1,r));
}

ll getminn(int x,int ti){
    ll now=x,ret=dp[MAXN-2];
    while(dep[x]-dep[top[now]]<=ti&&top[now]&&now!=0){
        ret=min(ret,query(1,dfn[top[now]],dfn[now]));
        now=fa[top[now]];
    }
    if(now==0||dep[x]-dep[now]>ti) return ret;
    int l=dfn[top[now]],r=dfn[now],mid=(l+r)>>1,ans=r;
    while(l<=r){
        int mid=(l+r)/2;
        if(dep[x]-dep[id[mid]]<=ti) ans=mid,r=mid-1;
        else l=mid+1;
    }
    ret=min(ret,query(1,ans,dfn[now]));
    return ret;
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<n;i++){
        int x,y;scanf("%d%d",&x,&y);
        addedge(y,x);
        addedge(x,y);
    }
    dfs1(1,0);num=0;
    dfs2(1,1);
    build(1,1,n);
    for(int i=1;i<=m;i++) g[i].read();
    sort(g+1,g+m+1,cmp);
    memset(dp,37,sizeof(dp));dp[1]=0;
    insert(1,1,0);
    for(int i=1;i<=m;i++){
        int co=g[i].co,ti=g[i].ti,x=g[i].x;
        if(x==1) continue;
        ll xx=getminn(x,ti);
        ll ret=getminn(x,ti)+co;
        dp[x]=min(dp[x],ret);
        insert(1,dfn[x],dp[x]);
    }
    cin>>q;
    while(q--){
        int x;scanf("%d",&x);
        printf("%lld\n",dp[x]);
    }
    return 0;
}

 

posted @ 2018-09-16 20:51  人间失格—太宰治  阅读(278)  评论(0编辑  收藏  举报