【JZOJ5248】花花的聚会
Description
注意测试数据中道路是
到
的单向道路,与题面恰好相反。
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
题解:
这个题目,首先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; }