UOJ#7. 【NOI2014】购票 点分治 斜率优化 凸包 二分

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ7.html

题解

这题是Unknown的弱化版。

如果这个问题出在序列上,那么显然可以CDQ分治 + 斜率优化 + 凸包上二分来做。

那么它出在树上?

点分治。

写挂了好多地方调了好久,自闭了。

代码

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f|=ch=='-',ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=200005;
const LL INF=1e18;
int n,type;
vector <int> e[N];
int fa[N];
LL d[N],p[N],q[N],lim[N];
LL dp[N];
int size[N],mx[N];
int RT,Size;
int vis[N];
void get_root(int x,int pre){
	size[x]=1,mx[x]=0;
	for (auto y : e[x])
		if (y!=pre&&!vis[y]){
			get_root(y,x);
			size[x]+=size[y];
			mx[x]=max(mx[x],size[y]);
		}
	mx[x]=max(mx[x],Size-size[x]);
	if (!RT||mx[x]<mx[RT])
		RT=x;
}
struct Point{
	LL x,y;
	Point(){}
	Point(LL _x,LL _y){
		x=_x,y=_y;
	}
}a[N];
int top;
vector <int> id;
LL Ask(LL p,LL lim){
	if (!top)
		return INF;
	int L=1,R=top-1,mid;
	LL ans=a[top].y-a[top].x*p;
	while (L<=R){
		mid=(L+R)>>1;
		if (p*(a[mid].x-a[mid+1].x)>=a[mid].y-a[mid+1].y)
			R=mid-1,ans=min(ans,a[mid].y-a[mid].x*p);
		else
			L=mid+1;
	}
	return ans;
}
bool cross(Point a,Point b,Point c){
	return (__int128)(b.x-a.x)*(c.y-a.y)-(__int128)(c.x-a.x)*(b.y-a.y)<0;
}
void Ins(Point p){
	while (top>1&&!cross(a[top-1],a[top],p))
		top--;
	a[++top]=p;
}
void upd_dp(int x){
	dp[x]=min(dp[x],Ask(p[x],lim[x])+q[x]+p[x]*d[x]);
}
vector <int> s;
void Get(int x,int pre){
	s.pb(x);
	for (auto y : e[x])
		if (y!=pre&&!vis[y])
			Get(y,x);
}
bool cmp(int a,int b){
	return lim[a]>lim[b];
}
void solve(int x){
	RT=0,get_root(x,0),x=RT;
	vector <int> id;
	id.clear();
	for (int i=x;!vis[i];i=fa[i])
		id.pb(i);
	vis[x]=1;
	int sp=Size-size[x];
	if (!vis[fa[x]]){
		Size=size[fa[x]]>size[x]?sp:size[fa[x]];
		solve(fa[x]);
	}
	for (auto y : id)
		if (y!=x&&d[y]>=lim[x])
			dp[x]=min(dp[x],dp[y]+p[x]*(d[x]-d[y])+q[x]);
	s.clear();
	for (auto y : e[x])
		if (!vis[y]&&y!=fa[x])
			Get(y,x);
	sort(s.begin(),s.end(),cmp);
	int i=0;
	top=0;
	for (auto x : id){
		while (i<s.size()&&lim[s[i]]>d[x])
			upd_dp(s[i++]);
		Ins(Point(d[x],dp[x]));
	}
	while (i<s.size())
		upd_dp(s[i++]);
	for (auto y : e[x])
		if (!vis[y]&&y!=fa[x]){
			Size=size[y]>size[x]?sp:size[y];
			solve(y);
		}
}
int main(){
	n=read(),type=read();
	For(i,2,n){
		fa[i]=read();
		d[i]=read()+d[fa[i]];
		p[i]=read();
		q[i]=read();
		lim[i]=d[i]-read();
		e[i].pb(fa[i]),e[fa[i]].pb(i);
		dp[i]=INF;
	}
	vis[0]=1,Size=n;
	solve(1);
	For(i,2,n)
		printf("%lld\n",dp[i]);
	return 0;
}

  

posted @ 2019-03-14 08:24  zzd233  阅读(257)  评论(0编辑  收藏  举报