• UOJ #7 NOI2014购票(点分治+cdq分治+斜率优化+动态规划)


      重写一遍很久以前写过的题。

      考虑链上的问题。容易想到设f[i]为i到1的最少购票费用,转移有f[i]=min{f[j]+(dep[i]-dep[j])*p[i]+q[i]} (dep[i]-dep[j]<=l[i])。套路的考虑若j转移优于k(dep[j]>dep[k]),则f[j]-dep[j]*p[i]<f[k]-dep[k]*p[i],f[j]-f[k]<(dep[j]-dep[k])*p[i],(f[j]-f[k])/(dep[j]-dep[k])<p[i]。若没有l[]的限制,对(dep[],f[])维护一个下凸壳即可。加入l[]的限制后,考虑使用cdq分治,右侧按dep[]-l[]从大到小排序,更新点时将新增的可以用来更新的点加入凸壳,并在凸壳上二分。

      拓展到树上,通过点分治实现一个树上cdq即可,同理要先处理靠近根的部分。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define N 200010
    #define int long long
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
    	int x=0,f=1;char c=getchar();
    	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    int n,p[N],t,fa[N],w[N],v[N],lim[N],deep[N],f[N],size[N],q[N],u[N],cnt2;
    bool flag[N];
    struct data{int to,nxt,len;
    }edge[N<<1];
    void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
    void dfs(int k)
    {
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (edge[i].to!=fa[k])
    	{
    		deep[edge[i].to]=deep[k]+edge[i].len;
    		dfs(edge[i].to);
    	}
    }
    void make(int k,int from)
    {
    	size[k]=1;
    	for (int i=p[k];i;i=edge[i].nxt) 
    	if (edge[i].to!=from&&!flag[edge[i].to])
    	{
    		make(edge[i].to,k);
    		size[k]+=size[edge[i].to];
    	}
    }
    int findroot(int k,int from,int s)
    {
    	int mx=0;
    	for (int i=p[k];i;i=edge[i].nxt) 
    	if (edge[i].to!=from&&!flag[edge[i].to]&&size[edge[i].to]>size[mx]) mx=edge[i].to;
    	if ((size[mx]<<1)>s) return findroot(mx,k,s);
    	else return k;
    }
    void build(int k,int from,int *id,int &cnt)
    {
    	id[++cnt]=k;
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (edge[i].to!=from&&!flag[edge[i].to]&&deep[edge[i].to]<deep[k]) build(edge[i].to,k,id,cnt);
    }
    long double slope(int x,int y){return (long double)(f[x]-f[y])/(deep[x]-deep[y]);}
    void get(int k,int from)
    {
    	u[++cnt2]=k;
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (edge[i].to!=from&&!flag[edge[i].to]) get(edge[i].to,k);
    }
    bool cmp(const int&a,const int&b)
    {
    	return deep[a]-lim[a]>deep[b]-lim[b];
    }
    void solve(int k)
    {
    	make(k,k);k=findroot(k,k,size[k]);flag[k]=1;
    	int id[N],cnt;id[cnt=1]=k;
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (!flag[edge[i].to]&&deep[edge[i].to]<deep[k])
    	{
    		build(edge[i].to,edge[i].to,id,cnt);
    		solve(edge[i].to);
    	}
    	for (int i=2;i<=cnt;i++) if (deep[k]-deep[id[i]]<=lim[k]) f[k]=min(f[k],f[id[i]]+w[k]*(deep[k]-deep[id[i]])+v[k]);
    	cnt2=0;
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (!flag[edge[i].to]) get(edge[i].to,edge[i].to);
    	sort(u+1,u+cnt2+1,cmp);
    	int t=0,tail=0;
    	for (int i=1;i<=cnt2;i++)
    	{
    		while (t<cnt&&deep[id[t+1]]>=deep[u[i]]-lim[u[i]])
    		{
    			while (tail>1&&slope(id[t+1],q[tail])>slope(q[tail],q[tail-1])) tail--;
    			q[++tail]=id[++t];
    		}
    		if (tail)
    		{
    			int l=1,r=tail-1,ans=tail;
    			while (l<=r)
    			{
    				int mid=l+r>>1;
    				if (slope(q[mid+1],q[mid])<w[u[i]]) ans=mid,r=mid-1;
    				else l=mid+1;
    			}
    			f[u[i]]=min(f[u[i]],f[q[ans]]+w[u[i]]*(deep[u[i]]-deep[q[ans]])+v[u[i]]);
    		}
    	}
    	cnt=0;
    	for (int i=p[k];i;i=edge[i].nxt)
    	if (!flag[edge[i].to]) solve(edge[i].to);
    }
    signed main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    	const char LL[]="%I64d
    ";
    #else
    	const char LL[]="%lld
    ";
    #endif
    	n=read();read();
    	for (int i=2;i<=n;i++)
    	{
    		fa[i]=read();
    		addedge(fa[i],i,read());
    		addedge(i,fa[i],0);
    		w[i]=read(),v[i]=read(),lim[i]=read();
    	}
    	dfs(1);
    	memset(f,60,sizeof(f));f[1]=0;
    	solve(1);
    	for (int i=2;i<=n;i++) printf(LL,f[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    面向对象编程思想-组合模式
    原生JS:Array对象详解
    一些XMLHttpRequest的例子代码
    详细解读XMLHttpRequest(一)同步请求和异步请求
    深入理解:JavaScript原型与继承
    轻松掌握:JavaScript状态模式
    轻松掌握:JavaScript装饰者模式
    轻松掌握:JavaScript享元模式
    轻松掌握:JavaScript模板方法模式
    回调函数的意义以及python实现
  • 原文地址:https://www.cnblogs.com/Gloid/p/10946513.html
Copyright © 2020-2023  润新知