【uoj7】 NOI2014—购票
http://uoj.ac/problem/7 (题目链接)
题意
给出一棵有根树,每次从一个节点出发可以买票到达它的一定范围内的祖先。问对于每一个点,到达根的最小花费是多少。
Solution
右转题解→_→:LCF
一些细节自己YY一下就好,看看代码也行。
细节
最好写读入优化?
代码
// uoj7 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define inf (1ll<<60) #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; inline LL gi() { LL x=0,f=1;char ch=getchar(); while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();} while (ch<='9' && ch>='0') {x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=200010; int n,T,cnt,a[maxn],par[maxn],head[maxn]; LL d[maxn],Q[maxn],P[maxn],L[maxn],ans[maxn]; struct node {LL w;int num;}t[maxn]; struct edge {int to,next;}e[maxn<<1]; namespace DP { int l,r,q[maxn]; void Clear() {l=1,r=0;} double slope(int i,int j) { return (double)(ans[i]-ans[j])/(d[i]-d[j]); } void push(int x) { while (l<r && slope(q[r-1],q[r])<slope(x,q[r])) r--; q[++r]=x; } void update(int x) { if (l>r) return; int ll=l,rr=r,y; while (ll<=rr) { int mid=(ll+rr)>>1; if (ll<mid && slope(q[mid-1],q[mid])<P[x]) y=mid,rr=mid-1; else if (rr>mid && slope(q[mid],q[mid+1])>P[x]) y=mid,ll=mid+1; else {y=mid;break;} } y=q[y]; ans[x]=min(ans[x],ans[y]+(d[x]-d[y])*P[x]+Q[x]); } } using namespace DP; namespace NodeDivide { int size[maxn],f[maxn],vis[maxn]; int Dargen,sum,dfn; bool cmp(node a,node b) { return a.w>b.w; } void caldargen(int x,int fa) { size[x]=1;f[x]=0; for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) { caldargen(e[i].to,x); size[x]+=size[e[i].to]; f[x]=max(f[x],size[e[i].to]); } f[x]=max(f[x],sum-size[x]); if (f[x]<f[Dargen]) Dargen=x; } void dfs(int x,int fa) { a[++dfn]=x; for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) dfs(e[i].to,x); } void work(int x) { vis[x]=1; if (!vis[par[x]]) { sum=size[par[x]]; Dargen=0;caldargen(par[x],x); work(Dargen); } Clear(); for (int j=par[x];!vis[j] && d[x]-d[j]<=L[x];j=par[j]) push(j); update(x); dfn=0; for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to] && e[i].to!=par[x]) dfs(e[i].to,x); for (int i=1;i<=dfn;i++) t[i]=(node){d[a[i]]-L[a[i]],a[i]}; sort(t+1,t+1+dfn,cmp); Clear(); for (int j=x,i=1;i<=dfn;i++) { for (;(!vis[j] || j==x) && t[i].w<=d[j];j=par[j]) push(j); update(t[i].num); } for (int i=head[x];i;i=e[i].next) if (e[i].to!=par[x] && !vis[e[i].to]) { sum=size[e[i].to],Dargen=0; caldargen(e[i].to,x); work(Dargen); } vis[x]=0; } void Init() { f[Dargen=0]=1<<30; sum=n;vis[0]=1; caldargen(1,0); work(Dargen); } } void link(int u,int v) { e[++cnt]=(edge){v,head[u]};head[u]=cnt; e[++cnt]=(edge){u,head[v]};head[v]=cnt; } int main() { n=gi(),T=gi(); for (int i=2;i<=n;i++) { par[i]=gi(),d[i]=gi(),P[i]=gi(),Q[i]=gi(),L[i]=gi(); d[i]+=d[par[i]];ans[i]=inf;link(i,par[i]); } NodeDivide::Init(); for (int i=2;i<=n;i++) printf("%lld\n",ans[i]); return 0; }
This passage is made by MashiroSky.