hdu 5956 The Elder 2016ACM/ICPC沈阳赛区现场赛I

Posted lqybzx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5956 The Elder 2016ACM/ICPC沈阳赛区现场赛I相关的知识,希望对你有一定的参考价值。

Problem Description
Once upon a time, in the mystical continent, there is a frog kingdom, ruled by the oldest frog, the Elder. The kingdom consists of N cities, numbered from east to west. The 1-th city, which is located to the east of others, is the capital. Each city, except the capital, links none or several cities to the west, and exactly one city to the east.
There are some significant news happening in some cities every day. The Elder wants to know them as soon as possible. So, that is the job of journalist frogs, who run faster than any other frog. Once some tremendous news happen in a city, the journalist in that city would take the message and run to the capital. Once it reach another city, it can either continue running, or stop at that city and let another journalist to transport. The journalist frogs are too young and simple to run a long distance efficiently. As a result, it takes L2 time for them to run through a path of length L. In addition, passing message requires P time for checking the message carefully, because any mistake in the message would make the Elder become extremely angry.
Now you are excited to receive the task to calculate the maximum time of sending a message from one of these cities to the capital.
 

Input
The first line of input contains an integer t, the number of test cases. t test cases follow. For each test case, in the first line there are two integers N (N ≤ 100000) and P (P ≤ 1000000). In the next N-1 lines, the i-th line describes the i-th road, a line with three integers u,v,w denotes an edge between the u-th city and v-th city with length w(w ≤ 100). 
 

Output
For each case, output the maximum time.
 

Sample Input
3 6 10 1 2 4 2 3 5 1 4 3 4 5 3 5 6 3 6 30 1 2 4 2 3 5 1 4 3 4 5 3 5 6 3 6 50 1 2 4 2 3 5 1 4 3 4 5 3 5 6 3
 

Sample Output
51 75 81
Hint
In the second case, the best transportation time is: ? The 2-th city: 16 = 4^2 ? The 3-th city: 72 = 4^2 + 30 + 5^2 ? The 4-th city: 9 = 3^2 ? The 5-th city: 36 = (3 + 3)^2 ? The 6-th city: 75 = (3 + 3)^2 +30 + 3^2 Consequently, the news in the 6-th city requires most time to reach the capital.

写了树分治双log的做法,被hdu卡掉了。

本来想看看别人怎么写的,结果发现网上目前只有暴力回溯的题解

一个菊花图,然后子节点特别优的话就能卡掉了。只是数据似乎没这么做。

先说一下树分治思路吧。

len[i]表示从1到i的长度

朴素方程f[i]=max(f[j]+(len[j]-len[i])^2)+p

然后假设j在k上面j比k优

(f[j]+(len[j]-len[i])^2)+p<(f[k]+(len[k]-len[i])^2)+p

移项得到斜率方程

((f[k]+len[k]*len[k])-(f[j]+len[j]*len[j]))/((len[k]-len[j])*2)>len[i]

右边有单调性

维护斜率单调减即可

具体做法是,对于某个重心,我们先分治重心上面的,再分治重心下面的。

分治的时候我们从重心往上跳到当前的根,将这段链维护一个凸包

重心下面的点按照到重心的长度排序,然后依次从凸包队首弹出元素直到最优,从队首转移即可

先丢个代码吧,对拍了一下应该没问题了,不过hdu上会T。现场应该是可以过的

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

update:卡了卡常后选了个没人评测没人抢评测资源的时候交,过了

原代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct line
{
	int s,t;
	int x;
	int next;
	bool flag;
}a[200001];
int head[100001];
int edge;
inline void add(int s,int t,int x)
{
	a[edge].next=head[s]; 
	head[s]=edge;
	a[edge].s=s;
	a[edge].t=t;
	a[edge].x=x;
	a[edge].flag=true;
}
long long len[100001];
long long f[100001];
int fa[100001];
inline bool cmp(int x,int y)
{
	return len[x]>len[y];
}
inline void getl(int d)
{
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(t!=fa[d])
		{
			fa[t]=d;
			len[t]=len[d]+a[i].x;
			getl(t);
		}
	}
}
int mini,minx;
int son[100001];
bool v[100001];
inline void find(int d,int s)
{
	son[d]=0;
	int i;
	int tmp=0;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(a[i].flag&&t!=fa[d])
		{
			find(t,s);
			son[d]+=(son[t]+1);
			tmp=max(tmp,son[t]+1);
		}
	}
	int mx=max(tmp,s-tmp-1);
	if(mx<minx)
	{
		minx=mx;
		mini=d;
	}
}
int sx[100001],dis[100001],px[100001];
int P;
inline double getk(int k,int j)
{
	return (double)((f[k]+len[k]*len[k])-(f[j]+len[j]*len[j]))/double(len[k]-len[j])/double(2);
}
int ps;
inline void gets(int d)
{
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(a[i].flag&&t!=fa[d])
		{  
			int t=a[i].t;  
			ps++;  
			px[ps]=t;  
			gets(t);  
		}  
	}
}
int q[100001];
inline void solve(int d,int size,int zx)
{
	if(size==1)
		return ;
	if(size==2)
	{
		if(len[zx]>len[d])
			f[zx]=min(f[zx],f[d]+(len[zx]-len[d])*(len[zx]-len[d])+P);
		return ;
	}
	int i;
	int ttx=son[zx];
	son[d]-=son[zx];
	for(i=head[zx];i!=0;i=a[i].next)
		a[i].flag=false;
	minx=2100000000;
	mini=0;
	find(d,son[d]+1);
	solve(d,son[d]+1,mini);
	for(i=head[zx];i!=0;i=a[i].next)
		a[i].flag=true;
//	ps=1;
//	px[ps]=zx;
	ps=0;
	gets(zx);
	sort(px+1,px+1+ps,cmp);
	int dx=zx;
	int l=1,r=0,lt=1;
	while(dx!=fa[d])
	{
		while(l<r&&getk(q[r-1],q[r])<getk(q[r],dx))  
			r--;  
		r++;
		q[r]=dx;
		dx=fa[dx];
	}
	for(i=1;i<=ps;i++)
	{
		while(l<r&&getk(q[l],q[l+1])>len[px[i]])  
			l++;
		if(px[i]==1)
			continue;
		f[px[i]]=f[q[l]]+(len[px[i]]-len[q[l]])*(len[px[i]]-len[q[l]])+P;
	}
	find(zx,ttx+1);
	for(i=head[zx];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(t==fa[zx])
			continue;
		minx=2100000000;
		mini=0;
		find(t,son[t]+1);
		solve(t,son[t]+1,mini);
	}
}
int main()
{
//	freopen("I.in","r",stdin);
//	freopen("I.out","w",stdout);
	int T;
//	scanf("%d",&T);
	T=read();
	while(T>0)
	{
		T--;
		int n;
		n=read();
		P=read();
		//scanf("%d%d",&n,&P);
		int i;
		int s,t,x;
		memset(head,0,sizeof(head));
		edge=0;
		for(i=1;i<=n-1;i++)
		{
			s=read();
			t=read();
			x=read();
			//scanf("%d%d%d",&s,&t,&x);
			edge++;
			add(s,t,x);
			edge++;
			add(t,s,x);
		}
		memset(len,0,sizeof(len));
		memset(fa,0,sizeof(fa));
		getl(1);
		memset(f,127/3,sizeof(f));
		f[1]=0;
		minx=2100000000;  
		mini=0;  
		find(1,n);  
		solve(1,n,mini);
		long long ans=0;
	//	for(i=1;i<=n;i++)
	//		printf("%d: %lld\n",i,f[i]);
		for(i=2;i<=n;i++)  
			ans=max(ans,f[i]);
		printf("%lld\n",ans-P);  
	}
	return 0;
}

AC代码:

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
/*inline int max(int x,int y)
{
	if(x>y)
		return x;
	return y;
}
inline int min(int x,int y)
{
	if(x<y)
		return x;
	return y;
}*/
inline long long max(long long x,long long y)
{
	if(x>y)
		return x;
	return y;
}
inline long long min(long long x,long long y)
{
	if(x<y)
		return x;
	return y;
}
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct line
{
	int s,t;
	int x;
	int next;
	bool flag;
}a[200001];
int head[100001];
int edge;
inline void add(int s,int t,int x)
{
	a[edge].next=head[s]; 
	head[s]=edge;
	a[edge].s=s;
	a[edge].t=t;
	a[edge].x=x;
	a[edge].flag=true;
}
long long lenx[100001];
long long len[100001];
//int len[100001];
//int f[100001];
long long f[100001];
int fa[100001];
inline bool cmp(int x,int y)
{
	return len[x]>len[y];
}
inline void getl(int d)
{
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(t!=fa[d])
		{
			fa[t]=d;
			len[t]=len[d]+a[i].x;
			getl(t);
		}
	}
}
int mini,minx;
int son[100001];
bool v[100001];
inline void find(int d,int s)
{
	son[d]=0;
	int i;
	int tmp=0;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(a[i].flag&&t!=fa[d])
		{
			find(t,s);
			son[d]+=(son[t]+1);
			tmp=max(tmp,son[t]+1);
		}
	}
	int mx=max(tmp,s-tmp-1);
	if(mx<minx)
	{
		minx=mx;
		mini=d;
	}
}
int sx[100001],dis[100001],px[100001];
int P;
/*inline double getk(int k,int j)
{
	return (double)((f[k]+len[k]*len[k])-(f[j]+len[j]*len[j]))/double(len[k]-len[j])/double(2);
}*/
inline bool check(int k1,int j1,int k2,int j2)
{
	return ((f[k1]+lenx[k1])-(f[j1]+lenx[j1]))*(len[k2]-len[j2])<((f[k2]+lenx[k2])-(f[j2]+lenx[j2]))*(len[k1]-len[j1]);
}
inline int checkk(int k,int j,int lenxt)
{
	return ((f[k]+lenx[k])-(f[j]+lenx[j]))>lenxt*2*(len[k]-len[j]);
}
int ps;
inline void gets(int d)
{
	int i;
	for(i=head[d];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(a[i].flag&&t!=fa[d])
		{  
			ps++;  
			px[ps]=t;  
			gets(t);  
		}  
	}
}
int q[100001];
inline void solve(int d,int size,int zx)
{
	if(size==1)
		return ;
	if(size==2)
	{
		if(len[zx]>len[d])
			f[zx]=min(f[zx],f[d]+(len[zx]-len[d])*(len[zx]-len[d])+P);
		return ;
	}
	int i;
	int ttx=son[zx];
	son[d]-=son[zx];
	for(i=head[zx];i!=0;i=a[i].next)
		a[i].flag=false;
	minx=2100000000;
	mini=0;
	find(d,son[d]+1);
	solve(d,son[d]+1,mini);
	for(i=head[zx];i!=0;i=a[i].next)
		a[i].flag=true;
//	ps=1;
//	px[ps]=zx;
	ps=0;
	gets(zx);
	sort(px+1,px+1+ps,cmp);
	int dx=zx;
	int l=1,r=0,lt=1;
	while(dx!=fa[d])
	{
	//	while(l<r&&getk(q[r-1],q[r])<getk(q[r],dx))  
		while(l<r&&check(q[r-1],q[r],q[r],dx))  
			r--;  
		r++;
		q[r]=dx;
		dx=fa[dx];
	}
	for(i=1;i<=ps;i++)
	{
	//	while(l<r&&getk(q[l],q[l+1])>len[px[i]])  
		while(l<r&&checkk(q[l],q[l+1],len[px[i]]))  
			l++;
		if(px[i]==1)
			continue;
		f[px[i]]=min(f[px[i]],f[q[l]]+(len[px[i]]-len[q[l]])*(len[px[i]]-len[q[l]])+P);
	}
	//find(zx,ttx+1);
	for(i=head[zx];i!=0;i=a[i].next)
	{
		int t=a[i].t;
		if(t==fa[zx])
			continue;
		minx=2100000000;
		mini=0;
		find(t,son[t]+1);
		solve(t,son[t]+1,mini);
	}
}
int main()
{
//	freopen("I.in","r",stdin);
//	freopen("I.out","w",stdout);
	int T;
//	scanf("%d",&T);
	T=read();
	while(T>0)
	{
		T--;
		int n;
		n=read();
		P=read();
		//scanf("%d%d",&n,&P);
		if(n==1)
		{
			printf("0\n");
			continue;
		}
		int i;
		int s,t,x;
		memset(head,0,sizeof(head));
		edge=0;
		for(i=1;i<=n-1;i++)
		{
			s=read();
			t=read();
			x=read();
			//scanf("%d%d%d",&s,&t,&x);
			edge++;
			add(s,t,x);
			edge++;
			add(t,s,x);
		}
		memset(fa,0,sizeof(fa));
		getl(1);
		for(i=1;i<=n;i++)
			lenx[i]=(long long)len[i]*(long long)len[i];
		memset(f,127/3,sizeof(f));
		f[1]=0;
		minx=2100000000;  
		mini=0;  
		find(1,n);  
		solve(1,n,mini);
		long long ans=0;
	//	for(i=1;i<=n;i++)
	//		printf("%d: %lld\n",i,f[i]);
		for(i=2;i<=n;i++)  
			ans=max(ans,f[i]);
		printf("%lld\n",ans-P);  
	}
	return 0;
}


以上是关于hdu 5956 The Elder 2016ACM/ICPC沈阳赛区现场赛I的主要内容,如果未能解决你的问题,请参考以下文章

hdu 5956 The Elder

[HDU5956]The Elder

HDU 5956 The Elder (树上斜率DP)

HDU - 59562016ACM/ICPC亚洲区沈阳站I - The Elder 树上斜率优化dp

HDU 6138 Fleet of the Eternal Throne(AC自动机)

HDU4057 Rescue the Rabbit(AC自动机+状压DP)