UOJ276 【清华集训2016】汽水

Link
先点分治,保存下以当前重心为一端且不经过其它中重心的路径,并按(overline w-k)排序。
然后二分答案,用双指针扫每个重心的路径,并维护下(overline w-k)最小的路径。
注意不能选来自同一子树的两条路径,因此我们再维护一个与(overline w-k)最小的路径来自不同子树的(overline w-k)最小的路径即可。

#include<cstdio>
#include<algorithm>
typedef long long i64;
const int N=50007,M=1000007;
int n,tot=1,All,root,cnt,num,head[N],ver[N<<1],next[N<<1],vis[N<<1],size[N],mx[N],st[N],ed[N];
i64 k,edge[N<<1],val[M];
struct node{i64 l;int d,r;}t[2][M];
int operator<(node a,node b){return a.l<b.l;}
int read(){int x;scanf("%d",&x);return x;}
i64 raed(){i64 x;scanf("%lld",&x);return x;}
void add(){int u=read(),v=read();i64 w=raed();ver[++tot]=v,next[tot]=head[u],edge[tot]=w,head[u]=tot,ver[++tot]=u,next[tot]=head[v],edge[tot]=w,head[v]=tot;}
void findroot(int u,int fa)
{
    size[u]=1,mx[u]=0;
    for(int i=head[u],v;i;i=next[i]) if(!vis[i]&&(v=ver[i])^fa) findroot(v,u),size[u]+=size[v],mx[u]=std::max(mx[u],size[v]);
    mx[u]=std::max(mx[u],All-size[u]),root=mx[u]<mx[root]? u:root;
}
void dfs(int u,int fa,i64 a,int b,int c)
{
    t[0][++num]=node{a,b,c},t[1][num]=node{-a,b,c};
    for(int i=head[u],v;i;i=next[i]) if(!vis[i]&&(v=ver[i])^fa) dfs(v,u,a+edge[i]-k,b+1,c);
}
void solve(int u)
{
    int id=++cnt;
    st[id]=num+1;
    for(int i=head[u];i;i=next[i]) if(!vis[i]) dfs(ver[i],u,edge[i]-k,1,ver[i]);
    ed[id]=num;
    for(int i=0;i<2;++i) std::sort(t[i]+st[id],t[i]+ed[id]+1);
    for(int i=head[u],v;i;i=next[i]) if(!vis[i]) vis[i^1]=1,mx[0]=All=size[v=ver[i]],findroot(v,root=0),solve(root);
}
int check(i64 lim)
{
    for(int i=0;i<2;++i)
    {
	for(int j=1;j<=num;++j)
	{
	    val[j]=-t[i][j].l-lim*t[i][j].d;
	    if(t[i][j].l<=0&&val[j]<0) return 1;
	}
	for(int j=1;j<=cnt;++j)
	{
	    int id1=0,id2=0;i64 mx1,mx2;
	    for(int l=st[j],r=ed[j],p=l,q=r;q>=l;--q)
	    {
		for(;p<=r&&t[i][q].l+t[i][p].l<=0;++p)
		{
		    int id=t[i][p].r;i64 x=val[p];
		    if(id1==id) { if(mx1>x) mx1=x; }
		    else if(!id1||mx1>x) id2=id1,mx2=mx1,id1=id,mx1=x;
		    else if(!id2||mx2>x) id2=id,mx2=x;
		}
		if(id1&&id1^t[i][q].r&&val[q]+mx1<0) return 1;
		if(id2&&id2^t[i][q].r&&val[q]+mx2<0) return 1;
	    }
	}
    }
    return 0;
}
int main()
{
    n=read(),k=raed();i64 l=1,r=1e13;
    for(int i=1;i<n;++i) add();
    mx[0]=All=n,findroot(1,0),solve(root);
    for(i64 mid;l<=r;) check(mid=(l+r)>>1)? r=mid-1:l=mid+1;
    printf("%lld",r);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12305676.html