题意:
有K的经费,询问从a->b 通过两种途径取得最大流量是多少
途径1: 加任意的边
途径2:扩充任意的边
思路:
对于每一个操作来说,如果a<=b那么加a->b的直接连的边必定最合算
如果a>b,那么有两种,第一是扩展原有的边。第二是加一条a->b的边,扩展a->b的边
一开始想复杂了,去搜了下,发现是个很模板的题,但是二分的左边界要处理好。否则会TLE。这题当入边的板子吧!入边入点在编号节点ID时总是感觉有些乱
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#define ll long long
using namespace std;
const int maxn = 200100;
const int inf = 0x3f3f3f3f;
int head[maxn],tot,pos,son[maxn];
int top[maxn],fp[maxn],fa[maxn],dep[maxn],siz[maxn],id[maxn];
int val[maxn];
int n;
struct Edge
{
int to,next,w;
} edge[maxn<<1];
void init()
{
tot = 0,pos = 1;
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
memset(siz,0,sizeof(siz));
}
void add_edge(int u,int v,int w)
{
edge[tot].w = w,edge[tot].to = v,edge[tot].next = head[u],head[u] = tot++;
}
void dfs1(int u,int f,int d)
{
dep[u] = d;
fa[u] = f,siz[u] = 1;
for(int i = head[u]; ~i; i = edge[i].next)
{
int v = edge[i].to;
if(v != f)
{
///把边权赋值给下面的点
val[v] = edge[i].w;
dfs1(v,u,d+1);
siz[u] += siz[v];
if( siz[v] > siz[son[u]])
son[u] = v;
}
}
}
void getpos(int u,int sp)
{
top[u] = sp;
id[u] = pos++;
///id是点的编号,fp[id[u]]是一个对于点与自身编号的映射
fp[id[u]] = u;
if(son[u] == -1)return ;
getpos(son[u],sp);
for(int i = head[u]; ~i ; i = edge[i].next)
{
int v = edge[i].to;
if(v != son[u] && v != fa[u])
getpos(v,v);
}
}
struct node
{
int l,r,mid;
ll minn;
} tree[maxn << 2];
void push_up(int i)
{
tree[i].minn = min(tree[i<<1].minn,tree[i<<1|1].minn);
}
void build(int i,int l,int r)
{
tree[i].l = l,tree[i].r = r;
tree[i].minn = inf;
tree[i].mid=(l+r) >>1;
if(l == r)
{
tree[i].minn = val[fp[l]];
return;
}
build(i<<1,l,tree[i].mid);
build(i<<1|1,tree[i].mid+1,r);
push_up(i);
}
void update(int i,int k,int val)
{
if(tree[i].l == k && tree[i].r == k)
{
tree[i].minn = val;
return;
}
int mid = tree[i].mid;
if(k <= mid) update(i<<1,k,val);
else update(i<<1|1,mid,val);
push_up(i);
}
ll query(int i,int l,int r)
{
if(tree[i].l >= l && tree[i].r <= r)
return tree[i].minn;
int mid = tree[i].mid;
if(r <= mid)
return query(i<<1,l,r);
else if(l > mid)
return query(i<<1|1,l,r);
else
{
return min(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
}
}
///找一个最小的权值作为限制
ll find_flow(int u,int v)
{
int tpu = top[u],tpv = top[v];
ll tmp = inf;
while(tpu != tpv)
{
///先走重链深度大的那条
if(dep[tpu] < dep[tpv])
{
swap(tpu,tpv),swap(u,v);
}
tmp = min(tmp,query(1,id[tpu],id[u]));
u = fa[tpu],tpu = top[u];
}
if(u == v) return tmp;
if(dep[u] > dep[v]) swap(u,v);
///此处入点与入边不同!; 入边则为查找id[son[u]] ,id [v]
///入点则为查找id[u],id[v].
///原因在于点权的赋值方法不同!
return min(tmp,query(1,id[son[u]],id[v]));
}
int allnum = 0;
///查找如今可以扩展的总流量是否可以满足使得小于MID的所有边都扩充到mid.
bool can_do(int i,int l,int r,int mid)
{
if(tree[i].l >= l && tree[i].r <= r && tree[i].minn >= mid)
{
return true;
}
if(tree[i].l == tree[i].r)
{
if(tree[i].minn >= mid)
return true;
allnum -= (mid-tree[i].minn);
if(allnum>= 0) return true;
return false;
}
if(r <= tree[i].mid)
return can_do(i<<1,l,r,mid);
else if(l > tree[i].mid)
return can_do(i<<1|1,l,r,mid);
else
return can_do(i<<1,l,tree[i].mid,mid)&&can_do(i<<1|1,tree[i].mid+1,r,mid);
}
bool find_flag(int u,int v,int mid)
{
int tpu = top[u],tpv = top[v];
while(tpu != tpv)
{
if(dep[tpu] < dep[tpv])
{
swap(tpu,tpv),swap(u,v);
}
if(!can_do(1,id[tpu],id[u],mid))
return false;
u = fa[tpu],tpu = top[u];
}
if(u == v) return true;
if(dep[u] > dep[v]) swap(u,v);
return can_do(1,id[son[u]],id[v],mid);
}
int a[maxn];
int main()
{
int T,cas = 1;
int x,y,k,a,b;
int m,u,v,w;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d%d",&n,&m);
for(int i =1; i < n; i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
dfs1(1,0,0);
getpos(1,1);
build( 1,1,pos );
printf("Case #%d:\n",cas++);
for(int i = 1;i <= m;i++)
{
scanf("%d%d%d%d%d",&x,&y,&k,&a,&b);
ll flow = find_flow(x,y);
if(k < min(a,b))
{
printf("%lld\n",flow);
}
else if(a <= b)
{
printf("%lld\n",flow+(ll)k/a);
}
else
{
ll ans = flow;
if(k > a)
ans += (k-a)/b+1;
int l = ans,r = 10000;
while(l <= r)
{
int mid = (l+r)>>1;
allnum = k/b;
if(find_flag(x,y,mid))
{
ans = mid,l = mid + 1;
}
else
r = mid - 1;
}
printf("%lld\n",ans);
}
}
}
return 0;
}