zoukankan      html  css  js  c++  java
  • bzoj3672: [Noi2014]购票

    传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3672

    思路:思路:首先不考虑树,也不考虑距离限制,假设是链上且无距离限制。
    设每个点到根的路径为d[i],两点之间路径长为dist(i,j)
    那么DP方程很显然f[i]=min(f[j]+dist(i,j)*p[i]+q[i])(i>j)
    f[i]=min(f[j]+d[i]*p[i]-d[j]*p[i]+q[i])
    这个式子显然可以斜率优化
    f[i]-d[i]*p[i]+d[j]*p[i]-q[i]=f[j]
    f[j]=p[i]*d[j]-d[i]*p[i]-q[i]+f[i]
    y   =k     x +    b
    那么我们只要让其截距最小即可
    如果以(d[j],f[j])为坐标,那么我们就需要一个下凸壳上的点
    用一个栈维护,每次二分斜率p[i]即可。


    然后考虑怎么变成树上的。
    用树链剖分,线段树维护下凸壳。
    线段树每个节点是一个vector,维护的是这一段上的点构成的下凸壳的坐标。
    询问就对每一段的下凸壳二分,取最小值即可


    至于距离限制,在树形DP的时候开一个栈,到一个点就把它压进栈,它的子树DP完了就退栈。
    这样栈里就按深度保存了根到当前点的路径上的所有点,二分最远距离,找到能到达的最远的点
    对这一段区间进行询问即可。


    时间复杂度O(n*log^3 n) 空间复杂度O(nlogn)

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ls (p<<1)
    #define rs ((p<<1)|1)
    #define mid ((l+r)>>1)
    #define pb(a) push_back(a)
    #define pob() pop_back()
    typedef long long ll;
    const int maxm=200010,maxn=200010;
    const double eps=1e-11;
    const ll inf=4611686018427387903LL;
    using namespace std;
    int n,m,pre[maxm],now[maxn],son[maxm],tot,modpp,tim;ll val[maxm],lim[maxm],p[maxn],q[maxn],f[maxn],dis[maxn],stk[maxn];
    int dep[maxn],top[maxn],siz[maxn],hson[maxn],fa[maxn],w[maxn],top1,num[maxn];
    void add(int a,int b,ll c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;}
    struct node{ll x,y;int id;};
    
    struct Tseg{
    	struct Tnode{
    		vector<node> stk;
    		double slope(node a,node b){return a.x==b.x?(double)inf:1.0*(a.y-b.y)/(a.x-b.x);}
    		ll getans(int i,int j){/*if (dis[i]<dis[j]) printf("fuckpp%lld %lld
    ",dep[i],dep[j]);*/return f[j]+(dis[i]-dis[j])*p[i]+q[i];}
    		void insert(node p){
    			int siz=stk.size();
    			while ((siz=stk.size())>1&&slope(stk[siz-1],stk[siz-2])>slope(stk[siz-1],p)) stk.pob();
    			stk.pb(p);
    		}
    		ll query(int id){
    			int siz=stk.size();ll res=inf;
    			if (!siz) return inf;
    			int l=1,r=siz;double k=(double)p[id];
    			//printf("%lld
    ",p[id]);
    			stk.push_back((node){stk[siz-1].x+1,inf,0});//防止二分时右边界出错 	
    			while (l<=r){
    				double lk=slope(stk[mid-1],stk[mid]),rk=slope(stk[mid],stk[mid+1]);
    				//printf("%d %d %d %lld %lld
    ",l,mid,r,stk[mid].x,stk[mid].y);
    				//printf("%lld
    ",f[1]);
    				if (k+eps<lk) r=mid-1;
    				else if (k>rk+eps) l=mid+1;
    				else{res=getans(id,stk[mid].id);break;}
    			}
    			//printf("res%lld
    ",res);
    			stk.pob();return res;
    		}
    	}t[maxn<<2];
    	void build(ll p,ll l,ll r){
    		t[p].stk.push_back((node){-1,inf,0});//防止二分时左边界出错 
    		if (l==r) return;
    		build(ls,l,mid),build(rs,mid+1,r);
    	}
    	void insert(int p,int l,int r,int x,node pp){
    		t[p].insert(pp);if (l==r) return;
    		if (x<=mid) insert(ls,l,mid,x,pp);
    		else insert(rs,mid+1,r,x,pp);
    	}
    	ll query(int p,int l,int r,int a,int b,int id){
    		//if (p==1) printf("%d %d %d %d
    ",l,r,a,b);
    		if (l==a&&r==b){
    			//printf("query%d %d %d %d
    ",l,r,a,b);
    			return t[p].query(id);}
    		if (b<=mid) return query(ls,l,mid,a,b,id);
    		else if (a>mid) return query(rs,mid+1,r,a,b,id);
    		else return min(query(ls,l,mid,a,mid,id),query(rs,mid+1,r,mid+1,b,id));
    	}
    	void insert(int x,node t){insert(1,1,n,x,t);};
    	ll query(int l,int r,int k){return query(1,1,n,l,r,k);};
    }T;
    
    void dfs1(int x){
    	siz[x]=1;
    	for (int y=now[x];y;y=pre[y]){
    		dep[son[y]]=dep[x]+1,dis[son[y]]=dis[x]+val[y],dfs1(son[y]);
    		if (siz[son[y]]>siz[hson[x]]) hson[x]=son[y];
    		siz[x]+=siz[son[y]];
    	}
    }
    
    void btree(int x,int tp){
    	w[x]=++tim,top[x]=tp;
    	if (hson[x]) btree(hson[x],tp);
    	for (ll y=now[x];y;y=pre[y])
    		if (son[y]!=hson[x])
    			btree(son[y],son[y]);
    }
    
    ll query(int a,int b){
    	int f1,f2,id=a;ll ans=inf;
    	a=fa[a];f1=top[a],f2=top[b];
    	while (f1!=f2){
    		if (dep[f1]<dep[f2]) swap(a,b),swap(f1,f2);
    		ans=min(ans,T.query(w[f1],w[a],id));
    		a=fa[f1],f1=top[a];
    	}
    	if (w[a]>w[b]) swap(a,b);
    	ans=min(ans,T.query(w[a],w[b],id));
    	return ans;
    }
    
    void dfs2(int x){
    	int anc=lower_bound(stk+1,stk+top1+1,dis[x]-lim[x])-stk;
    	//printf("%d %d
    ",x,num[anc]);
    	if (x!=1) f[x]=query(x,num[anc]);
    	T.insert(w[x],(node){dis[x],f[x],x});
    	stk[++top1]=dis[x],num[top1]=x;
    	/*if (x==1){
    		printf("pp%d %lld %d
    ",x,dis[x],num[top1]);
    		for (ll i=1;i<=top1;i++) printf("modpp%d %lld %d
    ",top1,stk[i],num[i]);
    	}*/
    	for (int y=now[x];y;y=pre[y]) dfs2(son[y]);
    	top1--;
    }
    
    int main(){
    	//freopen("ex_ticket2.in","r",stdin);//freopen("ex_ticket2.out","w",stdout);
    	//stk[1]=(poi){1,0},stk[2]=(poi){2,1},stk[3]=(poi){3,2};
    	//printf("%d
    ",lower_bound(stk+1,stk+4,(poi){1,0})-stk);
    	scanf("%d%d",&n,&modpp);T.build(1,1,n);
    	for (int i=2;i<=n;i++){ll c;	
    		scanf("%d%lld%lld%lld%lld",&fa[i],&c,&p[i],&q[i],&lim[i]),add(fa[i],i,c);
    		//if (fa[i]>1000) fa[i]-=999;//if (i==161) printf("%lld
    ",lim[i]);
    	}
    	dfs1(1),btree(1,1);
    	//for (int i=1;i<=n;i++) printf("%lld %lld
    ",i,dis[i]);
    	dfs2(1);
    	for (int i=2;i<=n;i++) printf("%lld
    ",f[i]);
    	return 0;
    }
    


  • 相关阅读:
    POJ 1795 DNA Laboratory
    CodeForces 303B Rectangle Puzzle II
    HDU 2197 本源串
    HDU 5965 扫雷
    POJ 3099 Go Go Gorelians
    CodeForces 762D Maximum path
    CodeForces 731C Socks
    HDU 1231 最大连续子序列
    HDU 5650 so easy
    大话接口隐私与安全 转载
  • 原文地址:https://www.cnblogs.com/thythy/p/5493500.html
Copyright © 2011-2022 走看看