hdu 4729 树链剖分

思路:这个树链剖分其实还是比较明显的。将边按权值排序后插入线段树,然后用线段树查找区间中比某个数小的数和,以及这样的数的个数。当A<=B时,就全部建新的管子。

对于A>B的情况比较 建一条由S->T的管子后将这根管子容量扩到最大能得到的容量  与   将所有预算都用来扩大管子容量不建新管子得到的最大容量 做比较 ,选最大的。

扩容量能得到的最大权值可以同过二分枚举答案,用树链剖分判断。

#include<set>

#include<map>

#include<cmath>

#include<queue>

#include<cstdio>

#include<vector>

#include<string>

#include<cstdlib>

#include<cstring>

#include<iostream>

#include<algorithm>

#define pb push_back

#define mp make_pair

#define Maxn 200010

#define Maxm 400010

#define LL __int64

#define Abs(x) ((x)>0?(x):(-x))

#define lson(x) (x<<1)

#define rson(x) (x<<1|1)

#define inf 100000

#define lowbit(x) (x&(-x))

#define clr(x,y) memset(x,y,sizeof(x))

#define Mod 1000000007

using namespace std;

int head[Maxn],vi[Maxn],dep[Maxn],w[Maxn],top[Maxn],son[Maxn],sz[Maxn],fa[Maxn],e,id;

int val[Maxn];

int num[Maxn],cnt;

struct Point{

    int val,i;

    int operator <(const Point &temp) const{

        return val<temp.val;

    }

}lis[Maxn];

struct Edge{

    int u,v,next;

    int val;

}edge[Maxn*3];

struct Tree{

    int l,r,c;

    int *p;

    int *q;

    int mid(){

        return (l+r)>>1;

    }

}tree[Maxn*3];

void init()

{

    clr(head,-1);clr(vi,0);

    e=0;id=0;

}

void add(int u,int v,int val)

{

    edge[e].u=u,edge[e].v=v,edge[e].val=val,edge[e].next=head[u],head[u]=e++;

}

void BuildTree(int l,int r,int po)

{

    tree[po].l=l,tree[po].r=r,tree[po].c=0;

    tree[po].p=new int[r-l+2];

    tree[po].q=new int[r-l+2];

    tree[po].q[0]=0;

    if(l==r)

        return ;

    int mid=tree[po].mid();

    BuildTree(l,mid,lson(po));

    BuildTree(mid+1,r,rson(po));

}

void update(int i,int c,int po)

{

    if(tree[po].l==tree[po].r){

        tree[po].p[++tree[po].c]=c;

        tree[po].q[tree[po].c]=tree[po].q[tree[po].c-1]+c;

        return ;

    }

    tree[po].p[++tree[po].c]=c;

    tree[po].q[tree[po].c]=tree[po].q[tree[po].c-1]+c;

    int mid=tree[po].mid();

    if(i<=mid)

        update(i,c,lson(po));

    else

        update(i,c,rson(po));

}

int getmin(int l,int r,int po)

{

    if(l<=tree[po].l&&tree[po].r<=r){

        return tree[po].p[1];

    }

    int mid=tree[po].mid();

    if(r<=mid)

        return getmin(l,r,lson(po));

    else if(l>=mid+1)

        return getmin(l,r,rson(po));

    else{

        return min(getmin(l,mid,lson(po)),getmin(mid+1,r,rson(po)));

    }

}

LL getans(int l,int r,LL val,int po)

{

    if(l<=tree[po].l&&tree[po].r<=r){

        int pos=lower_bound(tree[po].p+1,tree[po].p+tree[po].c+1,val)-tree[po].p;

        if(pos>tree[po].c){

            cnt+=tree[po].c;

            return tree[po].q[tree[po].c];

        }

        if(pos>1){

            cnt+=pos-1;

            return tree[po].q[pos-1];

        }

        return 0;

    }

    int mid=tree[po].mid();

    if(r<=mid)

        return getans(l,r,val,lson(po));

    else if(l>=mid+1)

        return getans(l,r,val,rson(po));

    else{

        return getans(l,mid,val,lson(po))+getans(mid+1,r,val,rson(po));

    }

}

void dfs(int u,int val)

{

    vi[u]=1;

    int i,v;

    son[u]=0,sz[u]=1;

    num[u]=val;

    for(i=head[u];i!=-1;i=edge[i].next){

        v=edge[i].v;

        if(vi[v]) continue;

        dep[v]=dep[u]+1;

        fa[v]=u;

        dfs(v,edge[i].val);

        if(sz[v]>sz[son[u]])son[u]=v;

        sz[u]+=sz[v];

    }

}

void build(int u,int ti)

{

    int i,v;

    w[u]=++id;top[u]=ti;vi[u]=1;

    lis[id].i=id,lis[id].val=num[u];

    if(son[u]) build(son[u],ti);

    for(i=head[u];i!=-1;i=edge[i].next){

        v=edge[i].v;

        if(vi[v]||v==son[u]) continue;

        build(v,v);

    }

}

LL need(LL val,int u,int v)

{

    int f1=top[u],f2=top[v];

    cnt=0;

    LL ans=0;

   // cout<<u<<" "<<f1<<" "<<v<<" "<<f2<<" "<<w[f1]<<" "<<w[u]<<endl;

    while(f1!=f2){

        if(dep[f1]<dep[f2]){

            swap(f1,f2),swap(u,v);

        }

        ans+=getans(w[f1],w[u],val,1);

        u=fa[f1];f1=top[u];

    }

    if(dep[u]>dep[v])

        swap(u,v);

    if(u!=v)

    ans+=getans(w[son[u]],w[v],val,1);

    //cout<<u<<" "<<v<<" "<<val<<" "<<cnt<<" "<<ans<<" "<<val*cnt-ans<<endl;

    ans=val*(LL)cnt-ans;

    return ans;

}

void calc(int u,int v,LL k,LL a,LL b)

{

    int x=u,y=v;

    int f1=top[u],f2=top[v];

    LL ans=10000000;

    while(f1!=f2){

        if(dep[f1]<dep[f2]){

            swap(f1,f2),swap(u,v);

        }

        ans=min(ans,(LL)getmin(w[f1],w[u],1));

        u=fa[f1];f1=top[u];

    }

    if(dep[u]>dep[v])

        swap(u,v);

    if(u!=v)

    ans=min(ans,(LL)getmin(w[son[u]],w[v],1));

    LL capacity=0;

    if(k<min(a,b)){

        printf("%I64d\n",ans);

        return ;

    }

    if(a<=b){

        printf("%I64d\n",k/a+ans);

        return ;

    }

    if(k>=a)

    capacity=(k-a)/b+1+ans;

    LL l,r,mid,temp;

    l=0,r=k/b+ans+1;

    while(l+1<r){

        mid=(l+r)>>1;

        temp=need(mid,x,y);

        temp*=b;

        if(temp<=k)

            l=mid;

        else

            r=mid-1;

    }

    if(r>=1)

    if(need(r,x,y)*b<=k&&r>l)

        l=r;

    printf("%I64d\n",max(capacity,l));

    return ;

}

int main()

{

    int t,n,m,i,j,u,v,val,q,a,b,k,Case=0;

    scanf("%d",&t);

    while(t--){

        init();

        scanf("%d%d",&n,&m);

        for(i=1;i<n;i++){

            scanf("%d%d%d",&u,&v,&val);

            add(u,v,val);

            add(v,u,val);

        }

        dfs(1,1200000000);

        memset(vi,0,sizeof(vi));

        build(1,1);

        sort(lis+1,lis+id+1);

        BuildTree(1,n,1);

        for(i=1;i<=n;i++){

            update(lis[i].i,lis[i].val,1);

        }

        printf("Case #%d:\n",++Case);

        for(i=1;i<=m;i++){

            scanf("%d%d%d%d%d",&u,&v,&k,&a,&b);

            calc(u,v,k,a,b);

        }

    }

    return 0;

}

 

你可能感兴趣的:(HDU)