• BZOJ4738 : 汽水


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

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

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

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

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

    时间复杂度$O(nlog 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;
    }
    

      

  • 相关阅读:
    表操作之数据类型——日期类型
    cocos2dx tableView 的使用
    lua中的循环
    lua中 后端发过来的 按位表示值,在前端中需要处理的函数
    lua 打印表方法
    近况
    lua开发
    4)数据结构和算法学习_链表
    3)数据结构和算法学习_链表
    使用VsCode断点调试TS
  • 原文地址:https://www.cnblogs.com/clrs97/p/7830548.html
Copyright © 2020-2023  润新知