BZOJ4738 : 汽水

二分答案$mid$,若存在一条路径满足$|ave-k|<mid$,则答案至多为$mid-1$。

若$ave\leq k$,则$\sum(w-k)\leq 0$,且$\sum(k-w-mid)<0$;若$ave\geq k$,那么同理。

预先树分治处理出所有到重心的路径的信息,并按$w-k$排序。

那么每次检查的时候,通过双指针满足第一个限制,维护最小值来满足第二个限制。

需要注意的是,不能选取两条来自同一棵子树的路径,这只需要维护来自不同子树的最小的两条路径即可。

时间复杂度$O(n\log n(\log n+\log w))$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=50010,M=1000010;
int n,i,x,y,g[N],nxt[N<<1],v[N<<1],ok[N<<1],ed,son[N],f[N],all,now;
ll z,K,w[N<<1],val[M],L,R,mid;
int st[N],en[N],cnt,cur;
struct P{ll x;int y,z;P(){}P(ll _x,int _y,int _z){x=_x,y=_y,z=_z;}}q[2][M];
inline bool cmp(const P&a,const P&b){return a.x<b.x;}
inline void add(int x,int y,ll z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;ok[ed]=1;}
void findroot(int x,int y){
son[x]=1;f[x]=0;
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y){
findroot(v[i],x);
son[x]+=son[v[i]];
if(son[v[i]]>f[x])f[x]=son[v[i]];
}
if(all-son[x]>f[x])f[x]=all-son[x];
if(f[x]<f[now])now=x;
}
void dfs(int x,int y,ll a,int b,int c){
q[0][++cur]=P(a,b,c);
q[1][cur]=P(-a,b,c);
for(int i=g[x];i;i=nxt[i])if(ok[i]&&v[i]!=y)dfs(v[i],x,a+w[i]-K,b+1,c);
}
void solve(int x){
int i,o=++cnt;
st[o]=cur+1;
for(i=g[x];i;i=nxt[i])if(ok[i])dfs(v[i],x,w[i]-K,1,v[i]);
en[o]=cur;
for(i=0;i<2;i++)sort(q[i]+st[o],q[i]+en[o]+1,cmp);
for(i=g[x];i;i=nxt[i])if(ok[i]){
ok[i^1]=0;
f[0]=all=son[v[i]];
findroot(v[i],now=0);
solve(now);
}
}
inline bool check(){
for(int i=0;i<2;i++){
for(int j=1;j<=cur;j++){
val[j]=-q[i][j].x-mid*q[i][j].y;
if(q[i][j].x<=0&&val[j]<0)return 1;
}
for(int j=1;j<=cnt;j++){
int l=st[j],r=en[j],x=r,y=l,az=0,bz=0;ll av,bv;
for(;x>=l;x--){
for(;y<=r&&q[i][x].x+q[i][y].x<=0;y++){
ll v=val[y];int z=q[i][y].z;
if(az==z){if(av>v)av=v;}
else if(!az||av>v)bv=av,bz=az,av=v,az=z;
else if(!bz||bv>v)bv=v,bz=z;
}
if(az&&az!=q[i][x].z&&val[x]+av<0)return 1;
if(bz&&bz!=q[i][x].z&&val[x]+bv<0)return 1;
}
}
}
return 0;
}
int main(){
scanf("%d%lld",&n,&K);
for(ed=i=1;i<n;i++)scanf("%d%d%lld",&x,&y,&z),add(x,y,z),add(y,x,z);
f[0]=all=n;findroot(1,now=0);solve(now);
L=1,R=1e13;
while(L<=R){
mid=(L+R)>>1;
if(check())R=mid-1;else L=mid+1;
}
return printf("%lld",R),0;
}

  

上一篇:【Mail】搭建邮件服务器(LAMP+Postfix+Dovcot+PostfixAdmin+Roundcubemail)


下一篇:ajax 跨域请求没有带上cookie 解决办法