听说这题要用到一个叫做“带权二分”的黑科技(名称来自于APIO2018讲课课件),那就让我来体验一下。
写了一发,感觉概念还好懂,但特别容易挂。
有几个要点:
1.要对输入数据加以随机扰动,不然会被三点共线的数据卡。
2.如果上次答案和这次答案的差很小,则直接输出这次答案,不然会被卡精度。
3.其实可以把权值和方案封装成一个struct,这样写起来会方便一点。
然后就抢下了洛谷运行时间rk1?真爽。
达成成就->做完九省联考Day2所有题目
// luogu-judger-enable-o2
#include<bits/stdc++.h>
typedef unsigned int ui;
inline ui R(){
static ui seed=time(0);
return seed^=seed>>5,seed^=seed<<17,seed^=seed>>13;
}
char ibuf[1<<25],*ih=ibuf,obuf[1<<25],*oh=obuf;
inline void read(int&x){
int f=1;for(;!isdigit(*ih);++ih)if(*ih=='-')f=-1;
for(x=0;isdigit(*ih);x=x*10+*ih++-48);x*=f;
}
const int N=3000005;
struct edge{int to,next;double w;}e[N<<1];
int da[N],id[N],xb,hh[N],i,k,n,x,y,v,a[N],b[N],c[N];
double ef[N],f[N],g[N],h[N];
void dfs(int x,int fa){
id[x]=++xb;da[xb]=id[fa];
for(int i=hh[x];i;i=e[i].next)if(e[i].to!=fa)ef[xb+1]=e[i].w,dfs(e[i].to,x);
}
int main(){
fread(ibuf,1,1<<25,stdin);
read(n);read(k);
for(i=1;i<n;++i){
read(x);read(y);read(v);
double z=(((long long)R()<<30|R())%19260817-9630408)/963040800000000.0;
e[++xb]=(edge){y,hh[x],v+z};hh[x]=xb;
e[++xb]=(edge){x,hh[y],v+z};hh[y]=xb;
}
xb=0;dfs(1,0);
double r=1e12,l=-1e12,m,lst;
for(;;){
m=(l+r)/2;
memset(f+1,0,n<<3);memset(g+1,0,n<<3);memset(h+1,0,n<<3);
memset(a+1,0,n<<2);for(i=1;i<=n;++i)b[i]=c[i]=1;
double z=-1e18;int su;
for(i=n;i;--i){
double x,of=f[da[i]],og=g[da[i]],oh=h[da[i]],u;
int oa=a[da[i]],ob=b[da[i]],oc=c[da[i]],v,y;
if(f[i]>h[i]-m && f[i]>g[i]-m)u=f[i],v=a[i];
else if(h[i]-m>g[i]-m)u=h[i]-m,v=c[i];
else u=g[i]-m,v=b[i];
if(of+u>f[da[i]])f[da[i]]=of+u,a[da[i]]=oa+v;
x=g[i]+ef[i];y=b[i];
if(of+x>g[da[i]])g[da[i]]=of+x,b[da[i]]=oa+y;
if(og+u>g[da[i]])g[da[i]]=og+u,b[da[i]]=ob+v;
if(oh+u>h[da[i]])h[da[i]]=oh+u,c[da[i]]=oc+v;
if(ob && og+x>h[da[i]])h[da[i]]=og+x,c[da[i]]=ob+y-1;
if(f[i]>z)z=f[i],su=a[i];
if(g[i]-m>z)z=g[i]-m,su=b[i];
if(h[i]-m>z)z=h[i]-m,su=c[i];
}
if(su==k+1 || (su && fabs(lst-z)<0.1)){
printf("%.0f\n",z+m*(k+1));
break;
}
if((z==0 && su==0) || (su && su<k+1))r=m;else l=m;
lst=z;
}
return 0;
}