题意

链接:https://cn.vjudge.net/problem/HDU-4729

给你n个点,然你求两个点s和t之间的最大流.而且你有一定的钱k,可以进行两种操作

1.在任意连个点之间建立一个单位1的流,费用a

2.将原先的流扩大1个单位,费用b

思路

题目已经说了是一棵树,那么树上两点的最大流就是两点路径上的最小值。其实两种操作各一次对最大流的贡献是相等的。我们分类讨论:

  1. 如果a<=b,直接算第一种方案即可,直接给s、t连一条边,对答案的贡献是k/a。
  2. 如果a>b,分两种情况。如果k>a,我们可以先操作一次方案一,即先给s、t连一条边,再对这条边进行扩大,这种方法对答案的贡献是(k-a)/b+1;如果k<=a,那么我们只扩大,肯定是先把最小的边扩大了,再看扩大新的最小边……直接暴力肯定不行,我们二分最大流x,我们可以扩大k/b次,那么判断一下在k/b次内能不能使得s到t的最小值>=x即可。具体实现我们可以递归处理,看代码。

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
#define il inline
const int inf = 0x3f3f3f3f, N = 1e5 + 5;
//适用于正负数,(int,long long,float,double)
template <class T>
il bool read(T &ret)
{
char c;
int sgn;
T bit=0.1;
if(c=getchar(),c==EOF) return 0;
while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
if(c==' '||c=='\n')
{
ret*=sgn;
return 1;
}
while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
ret*=sgn;
return 1;
}
// 线段树
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
int n, M, T;
int head[N], tot;
int top[N]; // top[v]即v所在重链的顶端结点
int fa[N]; // 父节点
int deep[N]; // 深度
int num[N]; // num[v] 以v为根的子树结点数
int p[N]; // p[v]为v的dfs位置
int fp[N]; // 与p相反
int son[N]; // 重子编号
int pos;
int mi[N << 2],val[N];
void pushUp(int rt)
{
mi[rt] = min(mi[rt << 1], mi[rt << 1 | 1]);
}
void build(int l, int r, int rt)
{
mi[rt] = inf;
if (l == r)
{
mi[rt]=val[fp[l]];
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushUp(rt);
}
int query(int L, int R, int l, int r, int rt)
{
if (L <= l && r <= R)
return mi[rt];
int m = (l + r) >> 1;
int ret = inf;
if (L <= m) ret = min(ret, query(L, R, lson));
if (R > m) ret = min(ret, query(L, R, rson));
return ret;
}
void update(int p, int x, int l, int r, int rt)
{
if (l == r)
{
mi[rt] = x;
return;
}
int m = (r + l) >> 1;
if (p <= m) update(p, x, lson);
else update(p, x, rson);
pushUp(rt);
} // 树链剖分
struct Edge
{
int to, next,w;
} edge[N * 2]; void init()
{
tot = 0;
pos = 0;
memset(head,-1,sizeof(head));
memset(son, -1,sizeof(son));
} void add(int u, int v,int w)
{
edge[tot].to = v;
edge[tot].next = head[u];
edge[tot].w=w;
head[u] = tot++;
} void dfs1(int u, int pre, int d)
{
deep[u] = d;
fa[u] = pre;
num[u] = 1;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (v != pre)
{
val[v]=edge[i].w;
dfs1(v, u, d + 1);
num[u] += num[v];
if (son[u] == -1 || num[v] > num[son[u]])
son[u] = v;
}
}
} void dfs2(int u, int sp)
{
top[u] = sp;
p[u] = pos++;
fp[p[u]] = u;
if (son[u] == -1)
return;
dfs2(son[u], sp);
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if (v != son[u] && v != fa[u])
dfs2(v, v);
}
} int queryMin(int u, int v)
{
int f1 = top[u], f2 = top[v];
int tmp = inf;
while (f1 != f2)
{
if (deep[f1] < deep[f2])
{
swap(f1, f2);
swap(u, v);
}
tmp = min(tmp, query(p[f1], p[u], 0, pos - 1, 1));
u = fa[f1];
f1 = top[u];
}
if (u == v) return tmp;
if (deep[u] > deep[v]) swap(u, v);
return min(tmp, query(p[son[u]], p[v], 0, pos - 1, 1));
} int all=0;
bool fun(ll L,ll R,ll l,ll r,ll rt,ll x)
{
if(L<=l&&r<=R&&mi[rt]>=x)
{
return true;
}
if(l==r)
{
if(mi[rt]>=x)
return true;
all-=(x-mi[rt]);
return all>=0;
}
int m=(l+r)>>1;
if(R<=m)
{
return fun(L,R,lson,x);
}
else if(L>m)
{
return fun(L,R,rson,x);
}
else
return fun(L,m,lson,x)&&fun(m+1,R,rson,x);
}
bool check(ll u,ll v,ll x)
{
int f1 = top[u], f2 = top[v];
while (f1 != f2)
{
if (deep[f1] < deep[f2])
{
swap(f1, f2);
swap(u, v);
}
if(!fun(p[f1], p[u], 0, pos - 1, 1,x))
return false;
u = fa[f1];
f1 = top[u];
}
if (u == v) return true;
if (deep[u] > deep[v]) swap(u, v);
return fun(p[son[u]], p[v], 0, pos - 1, 1,x);
}
signed main()
{
read(T);
int cs=0;
while (T--)
{
init();
read(n),read(M);
for(int i=0; i<n-1; i++)
{
ll u,v,w;
read(u),read(v),read(w);
add(u,v,w);
add(v,u,w);
}
dfs1(1, 0, 0);
dfs2(1, 1);
build(0, pos - 1, 1);
printf("Case #%lld:\n",++cs);
while (M--)
{
ll s,t,k,a,b;
read(s),read(t),read(k),read(a),read(b);
ll ans=queryMin(s,t);
if(k<min(a,b))
{
printf("%lld\n",ans);
}
else if(a<=b)
{
ans+=k/a;
printf("%lld\n",ans);
}
else
{
if(k>a)
ans+=(k-a)/b+1;
ll l=ans,r=10000,mid;
while(l<=r)
{
mid=(l+r)>>1;
all=k/b;
if(check(s,t,mid))
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
printf("%lld\n",ans);
} }
}
return 0;
}

HDU 4729 An Easy Problem for Elfness(树链剖分边权+二分)的更多相关文章

  1. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

  2. 数据结构(主席树):HDU 4729 An Easy Problem for Elfness

    An Easy Problem for Elfness Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (J ...

  3. HDU 4729 An Easy Problem for Elfness (主席树,树上第K大)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 题意:给出一个带边权的图.对于每一个询问(S , ...

  4. HDU 4729 An Easy Problem for Elfness(主席树)(2013 ACM/ICPC Asia Regional Chengdu Online)

    Problem Description Pfctgeorge is totally a tall rich and handsome guy. He plans to build a huge wat ...

  5. HDU 4729 An Easy Problem for Elfness 主席树

    题意: 给出一棵树,每条边有一个容量. 有若干次询问:\(S \, T \, K \, A \, B\),求路径\(S \to T\)的最大流量. 有两种方法可以增大流量: 花费\(A\)可以新修一条 ...

  6. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

  7. BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时 ...

  8. POJ3237 Tree 树链剖分 边权

    POJ3237 Tree 树链剖分 边权 传送门:http://poj.org/problem?id=3237 题意: n个点的,n-1条边 修改单边边权 将a->b的边权取反 查询a-> ...

  9. POJ2763 Housewife Wind 树链剖分 边权

    POJ2763 Housewife Wind 树链剖分 边权 传送门:http://poj.org/problem?id=2763 题意: n个点的,n-1条边,有边权 修改单边边权 询问 输出 当前 ...

随机推荐

  1. Kafka学习(一)

    官网 kafka.apache.org 集群部署 消息中间键 --> 分布式流式平台 Kafka Streaming Flume: 1个进程包含三个角色 source channle sink ...

  2. JUC-3-ConcurrentHashMap

    ConcurrentHashMap 锁分段机制  JDK1.8

  3. go语言设计模式之Concurrency workers pool

    worker.go package main import ( "fmt" "strings" ) type WorkerLauncher interface ...

  4. arp心得-caidachun

    arp地址解析协议,以前也学习过,一直有疑问,不同网段怎么解析,arp代理是什么,静态路由为什么可以配置下一跳是接口,而不是ip 1.同网段广播请求,单播应答 2.不同网络根据路由表的下一跳地址ip地 ...

  5. P4728 [HNOI2009]双递增序列

    题意 这个DP状态有点神. 首先考虑一个最暴力的状态:\(f_{i,j,k,u}\)表示第一个选了\(i\)个,第二个选了\(j\)个,第一个结尾为\(k\),第二个结尾为\(u\)是否可行. 现在考 ...

  6. linux umask计算方法

    1. umask用于设定默认的新建文件或目录的权限 查看umask当前值命令: umask -p 计算创建出的file权限方法: 如果umask值的每位数都是偶数,使用666按位减umask的值即可 ...

  7. nacos 的服务注册与发现

    nacos的服务注册于发现. 这个要求服务统一注册到注册中心,然后调用的时候就不需要通过ip来调用,直接通过服务名即可. 服务提供者 pom.xml配置,需要spring-cloud-starter- ...

  8. 实时聊天-websocket与ajax的区别于联系

     Ajax是什么? Ajax,即异步JavaScript和XML,是一种创建交互式网页应用的网页开发技术.通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新,这意味着可以在不重新加载整 ...

  9. 对systemV和systemd的简单理解(服务方面)

    在CentOS7(RHEL7)以后,服务从原来的由systemV管理机制升级到了systemd. 在sysV中,所有的服务脚本都放在/etc/rc.d/init.d/中,可以使用/etc/rc.d/i ...

  10. 前端笔记之Vue(三)生命周期&CSS预处理&全局组件&自定义指令

    一.Vue的生命周期 生命周期就是指一个对象的生老病死的过程. 用Vue框架,熟悉它的生命周期可以让开发更好的进行. 所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和 ...