• UOJ #276「清华集训2016」汽水


    为什么你们常数都这么小啊

    UOJ #276

    题意:在树上找一条链使得|边权平均值$ -k$|尽量小,$ n<=5e4$


    $ Solution:$

    首先二分答案$ ans$,即我们需要找一条链使得边权平均值 $in [-ans,ans]$

    我们分正负两半分开讨论

    先假设平均值$ in (0,ans]$

    将原树点分

    统计过根的所有链

    将这些链记录长度$len$,边数$sum$,所属子树标号$id$之后按长度排序

    添加一条链$(0,0,0)$,则过某点的链一定是某两条不在同一子树的链拼接而成

    两条链拼接合法当且仅当$ frac{len_i+len_j}{sum_i+sum_j} in (0,ans]$

    化简得$ len_i+len_j>0且len_i-ans·sum_i+len_j-ans·sum_j leq 0$

    我们记录后缀$ len_i-ans·sum_i$的最小值

    然后两个指针扫扫就好了

    注意存在不在同一子树的限制,我们需要同时记录不在同一子树的后缀最小值和次小值,这样才能合并

    如果平均值$ in [-ans,0]$,也用同样的方法维护前缀最大值和次大值即可

    注意各种边界的问题

    时间复杂度:$ O(n log n log val)$


    $ my code$

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector> 
    #define M 100010
    #define rt register int
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x = 0; char zf = 1; char ch = getchar();
        while (ch != '-' && !isdigit(ch)) ch = getchar();
        if (ch == '-') zf = -1, ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    int i,j,k,m,n,x,y,z,cnt,all,Root,nowmin;
    int F[M],L[M],N[M],a[M],size[M];ll c[M];
    bool vis[M];
    void add(int x,int y,ll z){
        a[++k]=y;c[k]=z;
        if(!F[x])F[x]=k;
        else N[L[x]]=k;
        L[x]=k; 
    }
    void getRoot(int x,int pre){
        size[x]=1;int Maxsize=0;
        for(rt i=F[x];i;i=N[i])if(a[i]!=pre&&!vis[a[i]]){
            getRoot(a[i],x);size[x]+=size[a[i]];
            Maxsize=max(Maxsize,size[a[i]]);
        }
        Maxsize=max(Maxsize,all-size[x]);
        if(Maxsize<nowmin)nowmin=Maxsize,Root=x;
    }
    int cs;
    vector<int>e[50010];
    void build(int x){
        int ls=all;vis[x]=1;
        for(rt i=F[x];i;i=N[i])if(!vis[a[i]]){
            all=(size[a[i]]>size[x]?ls-size[x]:size[a[i]]);
            nowmin=999999999;Root=233333;getRoot(a[i],x);
            e[x].push_back(Root);
            build(Root);
        }
    }
    struct chain{
        ll len;int sl,col;
        bool operator <(const chain s)const{
            return len<s.len;
        }
    }q[50010];int t;
    void Add(int col,int x,int pre,ll len,int sl){
        q[++t]={len,sl,col};
        for(rt i=F[x];i;i=N[i])if(a[i]!=pre&&!vis[a[i]])Add(col,a[i],x,len+c[i],sl+1);
    }
    int qzmax[50010][2],hzmin[50010][2],allsize=0;
    bool check(int x,ll ans){//0...x
        q[t=1]={0,0,0};vis[x]=1;
        for(rt i=F[x];i;i=N[i])if(!vis[a[i]])Add(a[i],a[i],x,c[i],1);
        sort(q+1,q+t+1);
        qzmax[1][0]=1;qzmax[1][1]=0;
        for(rt i=2;i<=t;i++){
            int id0=qzmax[i-1][0],id1=qzmax[i-1][1];
            qzmax[i][0]=id0;qzmax[i][1]=id1;
            if(q[i].len+ans*q[i].sl>q[id0].len+ans*q[id0].sl){
                if(q[i].col!=q[id0].col)qzmax[i][1]=qzmax[i][0];
                qzmax[i][0]=i;
            }
            else if(q[i].len+ans*q[i].sl>q[id1].len+ans*q[id1].sl||!id1){
                if(q[i].col!=q[id0].col)qzmax[i][1]=i;
            }
        }
        hzmin[t][0]=t;hzmin[t][1]=0;
        for(rt i=t-1;i>=1;i--){
            int id0=hzmin[i+1][0],id1=hzmin[i+1][1];
            hzmin[i][0]=id0;hzmin[i][1]=id1;
            if(q[i].len-ans*q[i].sl<q[id0].len-ans*q[id0].sl){
                if(q[i].col!=q[id0].col)hzmin[i][1]=hzmin[i][0];
                hzmin[i][0]=i;
            }
            else if(q[i].len-ans*q[i].sl<q[id1].len-ans*q[id1].sl||!id1){
                if(q[i].col!=q[id0].col)hzmin[i][1]=i;
            }        
        }
        int R=t;
        for(rt i=1;i<=t;i++){
            while((q[i].len+q[R].len>0||R==i)&&R)R--;
            if(R==0)break;if(R>=i)continue;
            int maxv=qzmax[R][0];
            if(q[qzmax[R][0]].col==q[i].col)maxv=qzmax[R][1];
            if(maxv==0)continue;
            if(q[i].len+q[i].sl*ans+q[maxv].len+ans*q[maxv].sl>0)return 1;
        }
        int L=1;
        for(rt i=t;i>=1;i--){
            while((q[i].len+q[L].len<0||L==i)&&L<=t)L++;
            if(L>t)break;if(L<=i)continue;
            int minv=hzmin[L][0];
            if(q[hzmin[L][0]].col==q[i].col)minv=hzmin[L][1];
            if(!minv)continue;
            if(q[i].len-q[i].sl*ans+q[minv].len-ans*q[minv].sl<0)return 1;        
        }
        bool res=0;
        for(rt i=0;i<e[x].size();i++)if(!res)res|=check(e[x][i],ans);
        return res;
    }
    int main(){
        n=read();ll w=read();
        for(rt i=1;i<n;i++){
            x=read();y=read();ll z=read();
            add(x,y,z-w);
            add(y,x,z-w);
        }
        nowmin=999999999;all=n;getRoot(1,1);
        int troot=Root;build(Root);
        memset(vis,0,sizeof(vis));
        ll L=0,R=10000000000000;
        while(L<=R){
            memset(vis,0,sizeof(vis));
            ll mid=(L+R)/2;
            if(check(troot,mid))R=mid-1;
            else L=mid+1;
        }
        write(R);
        return 0;
    }
  • 相关阅读:
    微信小程序支付接口之Django后台
    wx.request 请求与django
    ubuntu16.04 安装使用meld及问题
    微信小程序上传单张或多张图片
    ip地址掩码和位数对应关系表、子网掩码、网络地址、主机地址-yellowcong
    公网IP地址就一定是A类地址和B类地址吗?那C类地址就一定是私有地址吗?
    太厉害了,终于有人能把TCP/IP协议讲的明明白白了!
    linux/shell/bash 自动输入密码或文本
    shell case例子
    spring 配置Value常量(不支持到static上)
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10059572.html
Copyright © 2020-2023  润新知