【NOI2014】购票

  • 本文为博主原创,未经许可不得转载

首先推出状态转移方程:f[y]=f[x]+(dis[y]-dis[x])*p[y]+q[y]

然后这玩意可以斜率优化

我能说这道题是斜率优化上树吗?

然后用树分治解决

我感觉这玩意算得上是中序树分治

反正比以前写的后序树分治要奇怪

然后分治时维护斜率的凸包,更新答案时二分查找即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include<bits/stdc++.h>
#define FILE "read"
#define MAXN 200100
#define cmin(a,b) a=min(a,b)
#define cmax(a,b) a=max(a,b)
using namespace std;
typedef long long ll;
struct Point{
ll dis,f;
Point(ll a=0,ll b=0):dis(a),f(b){}
}st[MAXN];
struct node{int y,next;ll v;bool flag;}e[MAXN];
int n,opt,cg,top,len,fa[MAXN],Link[MAXN],cnt[MAXN],size[MAXN],F[MAXN];
ll p[MAXN],q[MAXN],lim[MAXN],dis[MAXN],f[MAXN];
double slop[MAXN];
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline ll read(){
ll x=0,f=1; char ch=getc();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();}
return x*f;
}
void insert(int x,int y,ll v){e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;}
double Slop(Point A,Point B){return (double)(A.f-B.f)/(A.dis-B.dis);}
bool cmp(int x,int y){return dis[x]-lim[x]>dis[y]-lim[y];}
void add(int x){
Point A(dis[x],f[x]);
double s=top?Slop(A,st[top]):1e18;
while(top>1&&s>=slop[top]) s=Slop(A,st[--top]);
st[++top]=A;
slop[top]=s;
}
Point find(double s){
int l=1,r=top,temp;
while(l<=r){
int mid=(l+r)>>1;
if(slop[mid]>=s) temp=mid,l=mid+1;
else r=mid-1;
}
return st[temp];
}
void dfs(int x){
for(int i=Link[x];i;i=e[i].next){
dis[e[i].y]=dis[x]+e[i].v;
dfs(e[i].y);
}
}
void getcg(int x,int Size,int &cg){
size[x]=1; F[x]=0;
for(int i=Link[x];i;i=e[i].next)if(!e[i].flag){
getcg(e[i].y,Size,cg);
size[x]+=size[e[i].y];
cmax(F[x],size[e[i].y]);
}
cmax(F[x],Size-size[x]);
if(F[x]<=F[cg]) cg=x;
}
void getpoints(int x){
cnt[++cnt[0]]=x;
for(int i=Link[x];i;i=e[i].next)
if(!e[i].flag) getpoints(e[i].y);
}
void solve(int root,int Size){
if(Size==1) return;
int cg=0; getcg(root,Size,cg);
for(int i=Link[cg];i;i=e[i].next)e[i].flag=1;
solve(root,Size-size[cg]+1);
cnt[0]=0; top=0;
for(int i=Link[cg];i;i=e[i].next)getpoints(e[i].y);
sort(cnt+1,cnt+cnt[0]+1,cmp);
for(int i=1,j=cg;i<=cnt[0];++i){
int x=cnt[i];
while(j!=fa[root]&&dis[j]>=dis[x]-lim[x]) add(j),j=fa[j];
if(top){
Point y=find(p[x]);
cmin(f[x],y.f+(dis[x]-y.dis)*p[x]+q[x]);
}
}
for(int i=Link[cg];i;i=e[i].next) solve(e[i].y,size[e[i].y]);
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); opt=read(); F[0]=1e9;
for(int i=2;i<=n;++i){
ll x=read(),v=read(); insert(x,i,v);
fa[i]=x; p[i]=read(); q[i]=read(); lim[i]=read();
}
for(int i=1;i<=n;++i) f[i]=1e18;
f[1]=0; dfs(1); solve(1,n);
for(int i=2;i<=n;++i) printf("%lld\n",f[i]);
return 0;
}
文章目录
,