zoukankan      html  css  js  c++  java
  • 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
    ",F[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    关于php操作windows计划任务管理
    学习: 导航器添加修饰符
    写给想学 Javascript 朋友的一点经验之谈
    Firebug Tutorial – Logging, Profiling and CommandLine (Part I)
    getElementsByClass(2)
    关于JavaScript的事件
    Javascript修改对象方法
    采用哪种方式(JS高级程序设计)
    getElementsByClass(1)
    让CSS更简洁、高效些,别再想当然了
  • 原文地址:https://www.cnblogs.com/silenty/p/9801021.html
Copyright © 2011-2022 走看看