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
51 75 81HintIn 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
原文:http://blog.csdn.net/lqybzx/article/details/52983551