BZOJ 3672: [Noi2014]购票

斜率优化+点分治(CDQ?)

首先处理一个分治中心到这一块子树的最高点(子树的根)的链上的DP值

优先分治处理包含根的子树,然后再处理其他子树

#include<cstdio>
#include<algorithm>
using namespace std;
long long root,Num,N,st,Top,cnt,last[1000005],sz[1000005],F_[1000005],p[1000005],q[1000005],lim[1000005],Dep[1000005],Fa[1000005],vis[1000005];
long long F[1000005];
struct node1{
	long long k,b;
}stack[1000005];
struct node2{
	long long x,val;
}E[1000005];
struct node{
	int to,next;
	long long val;
}e[1000005];
void add(int a,int b,long long c){
	e[++cnt].to=b;
	e[cnt].next=last[a];
	e[cnt].val=c;
	last[a]=cnt;
}
void dfs(int x,int fa,long long dep){
	sz[x]=1;
	Dep[x]=dep;
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (V==fa) continue;
		dfs(V,x,dep+e[i].val);
		sz[x]+=sz[V];
	}
}
void find_root(int x,int fa){
	sz[x]=1,F_[x]=0;
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (vis[V] || V==fa) continue;
		find_root(V,x);
		sz[x]+=sz[V];
		F_[x]=max(F_[x],sz[V]);
	}
	F_[x]=max(F_[x],N-sz[x]);
	if (F_[x]<F_[root]) root=x;
}
void Pre(int x,int fa){
	E[++Num]=(node2){x,Dep[x]-lim[x]};
	for (int i=last[x]; i; i=e[i].next){
		int V=e[i].to;
		if (vis[V] || V==fa) continue;
		Pre(V,x);
	}
}
bool cmp(node2 a,node2 b){
	return a.val>b.val;
}
double check(node1 a,node1 b){
	return ((double)a.b-b.b)/(b.k-a.k);
}
void insert(int x){
	node1 line=(node1){-Dep[x],F[x]};
	while (Top>1 && check(line,stack[Top])>=check(stack[Top],stack[Top-1])) Top--;
	stack[++Top]=line;
}
void Divide(int x,int S){
	if (S<=1) return;
	root=0,N=S;
	find_root(x,0);
	int Root=root;
	for (int i=last[Fa[root]]; i; i=e[i].next){
		int V=e[i].to;
		if (vis[V]) continue;
		if (V==Root) {
			vis[Root]=1;
			Divide(x,sz[x]-sz[Root]);
			break;
		}
	}
	for (int now=Fa[Root]; now!=Fa[x]; now=Fa[now])
		if (Dep[now]>=Dep[Root]-lim[Root]) F[Root]=min(F[Root],F[now]+1ll*(Dep[Root]-Dep[now])*p[Root]+q[Root]);
	Num=0;
	for (int i=last[Root]; i; i=e[i].next){
		int V=e[i].to;
		if (vis[V] || V==Fa[Root]) continue;
		Pre(V,Root);
	}
	sort(E+1,E+Num+1,cmp);
	Top=0,st=Root;
	for (int i=1; i<=Num; i++){
		int X=E[i].x;
		while (st!=Fa[x] && Dep[st]>=Dep[X]-lim[X]){
			insert(st);
			st=Fa[st];
		}
		if (Top){
			int L=1,R=Top;
			while (L<R){
				int mid=(L+R)>>1;
				double l,r;
				if (mid==Top) l=-1ll<<60;
				else l=check(stack[mid],stack[mid+1]);
				if (mid==1)  r=1ll<<60;
				else r=check(stack[mid],stack[mid-1]);
				if (p[X]>=l && p[X]<=r){
					L=mid;
					break;
				}
				else if (p[X]<l) L=mid+1;
				else R=mid-1;
			}
			F[X]=min(F[X],1ll*Dep[X]*p[X]+q[X]+stack[L].b+stack[L].k*p[X]);
		}
	}
	for (int i=last[Root]; i; i=e[i].next){
		int V=e[i].to;
		if (vis[V] || V==Fa[Root]) continue;
		Divide(V,sz[V]);
	}
}
int main(){
 	int n,t;
	scanf("%d%d",&n,&t);
	for (int i=2; i<=n; i++){
		long long Len;
		scanf("%lld%lld%lld%lld%lld",&Fa[i],&Len,&p[i],&q[i],&lim[i]);
		add(Fa[i],i,Len);
		add(i,Fa[i],Len);
	}
	dfs(1,0,0);
	for (int i=2; i<=n; i++) F[i]=1ll<<60;
	F_[0]=1e9;
	Divide(1,n);
	for (int i=2; i<=n; i++)
		printf("%lld\n",F[i]);
	return 0;
}

  

 

posted @ 2018-10-16 22:06  ~Silent  阅读(127)  评论(0编辑  收藏  举报
Live2D