bzoj3672: [Noi2014]購票

爲什麼我這麼慢!!!

這道題大概有兩種思路,樹分治和線段樹。

樹分治:使用類似cdq的方式,1:找重心,分裂,2:work(根所在的樹)3:用重心到根的點的答案更新重心的子樹,4:work(重心的子樹)。更新的時候維護一個下凸殼,在下凸殼上二分即可。(我寫了這個)

線段樹:同樣需要維護下凸殼,考慮在dfs時動態維護當前節點到根路徑上的區間下凸殼,這個用線段樹在每個節前維護一個支持回撤的單調棧,每次在棧上二分也是可以的。

時間複雜度O(nlog^2n)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 200005
#define ll long long
#define ld long double
using namespace std;
ll n,fa[N],dep[N],sz[N],b[N],len[N],Mx[N],p[N],q[N];
ll first[N],to[N],nxt[N],l,fl[N],lenth[N];
ll a[N],m,dp[N],st[N];
ll read()
{
	ll x=0;char c=getchar();
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x;
}
bool cmp(ll x,ll y){return b[x]>b[y];}
void link(ll x,ll y,ll z)
{
	to[++l]=y;lenth[l]=z;nxt[l]=first[x];first[x]=l;
}
void dfs(ll x)
{
	b[x]=max(0LL,dep[x]-len[x]);
	for (ll i=first[x];i;i=nxt[i])
	{
		dep[to[i]]=dep[x]+lenth[i];
		dfs(to[i]);
	}
}
void Get(ll x,ll y,ll &G)
{
	sz[x]=1;Mx[x]=0;
	for (ll i=first[x];i;i=nxt[i])
		if (!fl[i])
		{
			Get(to[i],y,G);
			sz[x]+=sz[to[i]];
			Mx[x]=max(Mx[x],sz[to[i]]);
		}
	Mx[x]=max(Mx[x],y-sz[x]);
	if (Mx[x]<=y/2) G=x;
}
void Dfs(ll x) 
{
	a[++m]=x;
	for (ll i=first[x];i;i=nxt[i])
		if (!fl[i])
			Dfs(to[i]);
}
bool pd(ll x,ll y,ll z)
{
	return (ld)(dp[z]-dp[x])/(dep[z]-dep[x])>(ld)(dp[z]-dp[y])/(dep[z]-dep[y]);
}
ll find(ll l,ll r,ll p)
{
	ll mid,ans=l;l++;
	while(l<=r)
	{
		mid=l+r>>1;
		if ( (ld)(dp[st[mid-1]]-dp[st[mid]])/(dep[st[mid-1]]-dep[st[mid]])> p)
			ans=mid,l=mid+1;
		else r=mid-1;
	}
	return st[ans];
}
void work(ll x,ll y)
{
	if (y==1) return;
	ll G=0;
	Get(x,y,G);
	for (ll i=first[G];i;i=nxt[i])
		fl[i]=1;
	work(x,y-sz[G]+1);
	m=0;
	for (ll i=first[G];i;i=nxt[i])
		Dfs(to[i]);
	sort(a+1,a+m+1,cmp);
	ll r=1,tp=0;
	while(r<=m&&b[a[r]]>dep[G]) r++;
	for (ll i=G;i!=fa[x];i=fa[i])
	{
		if (!(tp&&dp[i]>=dp[st[tp]]))
		{
			while(tp>=2&& pd(i,st[tp],st[tp-1]) ) tp--;
			st[++tp]=i;
		}
		for (;r<=m&&(b[a[r]]>dep[fa[i]]||i==x);r++)
		{
			ll t=find(1,tp,p[a[r]]);
			t=dp[t]+(dep[a[r]]-dep[t])*p[a[r]]+q[a[r]];
			dp[a[r]]=min(dp[a[r]],t);
		}
	}
	for (ll i=first[G];i;i=nxt[i])
		work(to[i],sz[to[i]]);
}
int main()
{
	n=read();read();dp[1]=0;
	for (ll i=2,o;i<=n;i++)
	{
		fa[i]=read();o=read();p[i]=read();q[i]=read();len[i]=read();
		link(fa[i],i,o);dp[i]=1e18;
	}
	dfs(1);work(1,n);
	for (ll i=2;i<=n;i++)
		printf("%lld\n",dp[i]);
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章