bzoj3242: [Noi2013]快餐店

——來自一個失去夢想的鹹魚miaom

考慮海蜇基環樹的一般套路,在確定快餐店位置的情況下,最優解中環上必有一條邊是廢的。思考枚舉這條邊,我們需要在最快的時間求剩餘部分的直徑。當前答案就是直徑/2,證明非常簡單,就離快餐店最遠的點一定是直徑端點。這個東西可以通過雙指針單調隊列維護,達到O(n)複雜度。然後我就失去了夢想,直接線段樹水過了。

線段樹做法如下:先搞出那個環,重複一遍變成序列問題,詢問一個區間的直徑。有一種情況直徑不在環上,可以預處理。另一種情況至於環上點子樹最深的點有關,使用線段樹維護那個點的深度±在環中的位置區間合併,具體見代碼~

至於怎麼搞環,不是重點,一波dfs即可(其實拓撲排序也可以)。

#include<bits/stdc++.h>
#define N 200005
#define ll long long
using namespace std;
ll n,x,y,z,m;
ll fst[N],to[N*2],nxt[N*2],len[N],l;
ll vis[N],fa[N],flag,flag1,flag2,fl[N];
ll a[N];ll b[N],d[N],M1[N],Mx[N],dep[N],vl[N],vr[N],Ans,ly;
void link(ll x,ll y,ll z)
{
	to[++l]=y;len[l]=z;nxt[l]=fst[x];fst[x]=l;
	to[++l]=x;len[l]=z;nxt[l]=fst[y];fst[y]=l;
}
void dfs(ll x)
{
	//cout<<x<<endl;
	vis[x]=1;
	for (ll i=fst[x];i;i=nxt[i])
		if (to[i]!=fa[x])
		{
			if (vis[to[i]])
			{
				if (!flag)
				flag=x,flag1=to[i],flag2=len[i];
			}
			else
			{
				dep[to[i]]=dep[x]+len[i];
				fa[to[i]]=x;
				dfs(to[i]);
				//fl[x]+=fl[to[i]];
			}
		}
}
void Dfs(ll x)
{
	Mx[x]=0;
	M1[x]=0;
	for (ll i=fst[x];i;i=nxt[i])
		if (to[i]!=fa[x]&&fl[to[i]]==0)
		{
			fa[to[i]]=x;
			Dfs(to[i]);
			Mx[x]=max(Mx[x],max(Mx[to[i]],M1[x]+M1[to[i]]+len[i]));
			M1[x]=max(M1[x],M1[to[i]]+len[i]);
		}
}
struct T
{
	ll l,r,a;
}nd[N*8],now;
T operator+(T a,T b)
{
	return (T){max(a.l,b.l),max(a.r,b.r),max(max(a.a,b.a),a.l+b.r)};
}
void build(ll k,ll l,ll r)
{
	if (l==r)
	{
		nd[k]=(T){vl[l],vr[l],0};
		return;
	}
	ll mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	nd[k]=nd[k<<1]+nd[k<<1|1];
}
void qry(ll k,ll l,ll r,ll x,ll y)
{
	if (x<=l&&r<=y)
	{
		if (now.a==-1) now=nd[k];
		else now=now+nd[k];
		return;
	}
	ll mid=l+r>>1;
	if (x<=mid) qry(k<<1,l,mid,x,y);
	if (y>mid) qry(k<<1|1,mid+1,r,x,y);
}
int main()
{
	scanf("%lld",&n);
	for (ll i=1;i<=n;i++)
	{
		scanf("%lld%lld%lld",&x,&y,&z);
		link(x,y,z);
	}
	dfs(1);
	for (;flag!=flag1;flag=fa[flag])
		fl[a[++m]=flag]=1,b[m]=dep[flag]-dep[fa[flag]];
		
	fl[a[++m]=flag1]=1;b[m]=flag2;
	for (ll i=1;i<=m;i++)
		fa[a[i]]=0,Dfs(a[i]),ly=max(ly,Mx[a[i]]);
	
	for (ll i=1;i<=m;i++)
		a[i+m]=a[i],b[i+m]=b[i];
	
	for (ll i=1;i<=2*m;i++)
	{
		d[i]=d[i-1]+b[i-1];
		vl[i]=M1[a[i]]-d[i]; 
		vr[i]=M1[a[i]]+d[i];
	}
	build(1,1,2*m);
	Ans=100000000000000L;
	for (ll i=1;i<=m;i++)
	{
		now=(T){0,0,-1};
		qry(1,1,2*m,i,i+m-1);
		Ans=min(Ans,max(now.a,ly));
	}
	
	printf("%lld.%d\n",Ans/2,Ans&1?5:0);
	
}


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