[HDU4729]An Easy Problem for Elfness

Posted skylee03

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDU4729]An Easy Problem for Elfness相关的知识,希望对你有一定的参考价值。

[HDU4729]An Easy Problem for Elfness

题目大意:

给你一棵(n(nle10^5))个点的树,树上每条边都有容量。

(m(mle10^5))次询问,每次询问你有(k)的预算,可以花(a)的代价在任意两点间建一条流容量为(1)的边(包括重边),或者花费(b)的代价将某条边的容量加(1),问在不超过预算的情况下,从(s)(t)的最大流量。

思路:

首先,考虑没有(k,a,b)的情况,答案就是(s,t)路径上的权值最小值(min)

对于(ale b)的情况,由于我们每在(s)(t)之间新建一条边都能增加(1)的容量,则我们把所有的预算都用来新建边肯定是最优策略。答案是(min+lfloorfrac ka floor)

对于(a>b)的情况,我们有以下两种可能最优的策略:

  1. 花费(a)的代价新建一条边,然后用剩下的所有预算扩充这条新边的容量。
  2. 不断将路径上最小边扩充(1)的容量。

对于第一种策略,我们不难得到答案就是(min+1+lfloorfrac{k-a}b floor)

对于第二种策略,我们可以二分答案(mid)。设路径上边容量(<mid)的边数有(c)个,权值和为(w)。则(c imes mid-w)就是需要扩充的容量之和。若(c imes mid-wlelfloorfrac kb floor),则(ans>=mid),反之(ans<mid)

上文提及的边数与权值和可以用树上主席树方便地求得。

时间复杂度(mathcal O(nlog^2n))

源代码:

#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
#include<forward_list>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
using int64=long long;
constexpr int N=1e5+1,logN=17,logW=15,W=10000;
using Edge=std::pair<int,int>;
std::forward_list<Edge> e[N];
inline void add_edge(const int &u,const int &v,const int &w) {
    e[u].emplace_front((Edge){v,w});
    e[v].emplace_front((Edge){u,w});
}
int n,m,s,t,k,a,b;
class FotileTree {
    #define mid ((b+e)>>1)
    private:
        struct Node {
            int sum;
            int64 val;
            int left,right;
            std::pair<int,int64> operator + (const Node &rhs) const {
                return std::make_pair(sum+rhs.sum,val+rhs.val);
            }
            friend std::pair<int,int64> operator - (const std::pair<int,int64> &lhs,const Node &rhs) {
                return std::make_pair(lhs.first-rhs.sum,lhs.second-rhs.val);
            }
            Node operator * (const int &rhs) const {
                return {sum*rhs,val*rhs};
            }
        };
        Node node[N*logW];
        int sz,new_node(const int &p) {
            node[++sz]=node[p];
            return sz;
        }
    public:
        int root[N];
        void reset() {
            sz=0;
        }
        void insert(int &p,const int &b,const int &e,const int &x) {
            p=new_node(p);
            node[p].sum++;
            node[p].val+=x;
            if(b==e) return;
            if(x<=mid) insert(node[p].left,b,mid,x);
            if(x>mid) insert(node[p].right,mid+1,e,x);
        }
        std::pair<int,int64> query(const int &p,const int &q,const int &r,const int &b,const int &e,const int64 &x) const {
            if(node[p]+node[q]-node[r]*2==std::make_pair(0,0ll)) return std::make_pair(0,0);
            if(x>=e) return node[p]+node[q]-node[r]*2;
            if(x<=mid) {
                return query(node[p].left,node[q].left,node[r].left,b,mid,x);
            } else {
                const auto p1=query(node[p].left,node[q].left,node[r].left,b,mid,x);
                const auto p2=query(node[p].right,node[q].right,node[r].right,mid+1,e,x);
                return std::make_pair(p1.first+p2.first,p1.second+p2.second);
            }
        }
    #undef mid
};
FotileTree tr;
void reset() {
    for(register int i=1;i<=n;i++) e[i].clear();
    tr.reset();
}
inline int lg2(const float &x) {
    return ((unsigned&)x>>23&255)-127;
}
int anc[N][logN],min[N][logN]={{INT_MAX}},dep[N];
void dfs(const int &x,const int &par) {
    anc[x][0]=par;
    dep[x]=dep[par]+1;
    for(register int i=1;i<=lg2(dep[x]);i++) {
        anc[x][i]=anc[anc[x][i-1]][i-1];
        min[x][i]=std::min(min[x][i-1],min[anc[x][i-1]][i-1]);
    }
    for(auto &i:e[x]) {
        const int &y=i.first,&w=i.second;
        if(y==par) continue;
        tr.insert(tr.root[y]=tr.root[x],0,W,min[y][0]=w);
        dfs(y,x);
    }
}
int get_min(int x,int y) {
    if(dep[x]<dep[y]) std::swap(x,y);
    int ret=INT_MAX;
    for(register int i=lg2(dep[x]-dep[y]);i>=0;i--) {
        if(dep[anc[x][i]]>=dep[y]) {
            ret=std::min(ret,min[x][i]);
            x=anc[x][i];
        }
    }
    if(x==y) return ret;
    for(register int i=lg2(dep[x]);i>=0;i--) {
        if(anc[x][i]!=anc[y][i]) {
            ret=std::min(ret,min[x][i]);
            ret=std::min(ret,min[y][i]);
            x=anc[x][i];
            y=anc[y][i];
        }
    }
    ret=std::min(ret,min[x][0]);
    ret=std::min(ret,min[y][0]);
    return ret;
}
inline int get_lca(int x,int y) {
    if(dep[x]<dep[y]) std::swap(x,y);
    for(register int i=lg2(dep[x]-dep[y]);i>=0;i--) {
        if(dep[anc[x][i]]>=dep[y]) {
            x=anc[x][i];
        }
    }
    if(x==y) return x;
    for(register int i=lg2(dep[x]);i>=0;i--) {
        if(anc[x][i]!=anc[y][i]) {
            x=anc[x][i];
            y=anc[y][i];
        }
    }
    return anc[x][0];
}
inline bool check(const int64 &mid) {
    const auto tmp=tr.query(tr.root[s],tr.root[t],tr.root[get_lca(s,t)],0,W,mid);
    return tmp.first*mid-tmp.second<=k/b;
}
int main() {
    const int T=getint();
    for(register int i=1;i<=T;i++) {
        printf("Case #%d:
",i);
        n=getint(),m=getint();
        for(register int i=1;i<n;i++) {
            const int u=getint(),v=getint(),w=getint();
            add_edge(u,v,w);
        }
        dfs(1,0);
        for(register int i=0;i<m;i++) {
            s=getint(),t=getint(),k=getint(),a=getint(),b=getint();
            const int min=get_min(s,t);
            if(a<=b) {
                printf("%lld
",min+(int64)k/a);
                continue;
            }
            int64 l=min+(int64)k/a+1,r=min+(int64)k/b;
            while(l<=r) {
                const int64 mid=(l+r)>>1;
                if(check(mid)) {
                    l=mid+1;
                } else {
                    r=mid-1;
                }
            }
            printf("%lld
",k>=a?std::max(min+1+(int64)(k-a)/b,l-1):l-1);
        }
        reset();
    }
    return 0;
}

以上是关于[HDU4729]An Easy Problem for Elfness的主要内容,如果未能解决你的问题,请参考以下文章

HDU 4729 An Easy Problem for Elfness(树链剖分边权+二分)

HDOJ4729 An Easy Problem for Elfness

HDU 2132 An easy problem

HDU 2123 An easy problem

hdu 2601 An easy problem

hdu 5572 An Easy Physics Problem 圆+直线