题目大意
有一棵树,给你边的容量。每次给你s,t,k,a,b,求s到t的最大流。k是总预算,a是加一条边的费用(容量为1),b是扩充一条边的费用。
我的做法
LCA+树套可持久化线段树
建立权值线段树,每个节点保存这个区间内边的数目,这个区间内边容量之和。初始的流量flow就是s到t的最小值。
接下来要分类讨论
1.a<=b:就拿全部预算加边,答案为flow+k/a。
2.a>b:
(1)加一条边,然后扩充这条边,答案为flow+(k-a)/b+1。
(2)把这k/b此机会全部扩充边,答案为扩充后容量最小的边。这里在线段树上二分去寻找答案。
#include<cstdio>
#include<cstring>
#include<list>
using namespace std;
typedef long long ll;
int ls[5000010];
int rs[5000010];
ll num[5000010];
ll sum[5000010];
int cnt;
int root[100010];
void mt(int p)
{
num[p]=num[ls[p]]+num[rs[p]];
sum[p]=sum[ls[p]]+sum[rs[p]];
}
int build(int l,int r)
{
int p=++cnt;
ls[p]=rs[p]=0;
num[p]=sum[p]=0;
if(l==r)
return p;
int mid=(l+r)>>1;
ls[p]=build(l,mid);
rs[p]=build(mid+1,r);
}
int insert(int p1,int x,int l,int r)
{
int p2=++cnt;
ls[p2]=ls[p1];
rs[p2]=rs[p1];
num[p2]=num[p1];
sum[p2]=sum[p1];
if(l==r)
{
num[p2]++;
sum[p2]+=l;
return p2;
}
int mid=(l+r)>>1;
if(x<=mid)
ls[p2]=insert(ls[p1],x,l,mid);
else
rs[p2]=insert(rs[p1],x,mid+1,r);
mt(p2);
return p2;
}
int find(int p1,int p2,int p3,int l,int r)
{
if(l==r)
return l;
int s=num[ls[p1]]+num[ls[p2]]-2*num[ls[p3]];
int mid=(l+r)>>1;
if(s)
return find(ls[p1],ls[p2],ls[p3],l,mid);
return find(rs[p1],rs[p2],rs[p3],mid+1,r);
}
ll solve(int p1,int p2,int p3,int k,ll num_,ll sum_,int l,int r)
{
if(l==r)
return l-1;
int mid=(l+r)>>1;
ll tmp_num=num[ls[p1]]+num[ls[p2]]-2*num[ls[p3]];
ll tmp_sum=sum[ls[p1]]+sum[ls[p2]]-2*sum[ls[p3]];
if((num_+tmp_num)*mid-(sum_+tmp_sum)>k)
return solve(ls[p1],ls[p2],ls[p3],k,num_,sum_,l,mid);
return solve(rs[p1],rs[p2],rs[p3],k,num_+tmp_num,sum_+tmp_sum,mid+1,r);
}
struct tree
{
int f;
int top;
int w;
int deep;
int size;
int son;
int msize;
int v;
tree()
{
v=f=top=w=deep=size=son=msize=0;
}
};
tree a[100010];
list<pair<int,int> > l[100010];
int cnt2;
void dfs1(int x,int f,int deep)
{
a[x].v=a[x].f=a[x].top=a[x].w=a[x].deep=a[x].size=a[x].son=a[x].msize=0;
a[x].f=f;
a[x].deep=deep;
a[x].size=1;
list<pair<int,int> >::iterator p;
int v;
for(p=l[x].begin();p!=l[x].end();p++)
if((v=p->first)!=f)
{
dfs1(v,x,deep+1);
a[x].size+=a[v].size;
if(a[v].size>a[x].msize)
{
a[x].msize=a[v].size;
a[x].son=v;
a[x].v=p->second;
}
}
}
void dfs2(int x,int top,int d)
{
a[x].w=++cnt2;
a[x].top=top;
root[a[x].w]=insert(root[a[a[x].f].w],d,0,10000);
if(!a[x].son)
return;
dfs2(a[x].son,top,a[x].v);
int v;
list<pair<int,int> >::iterator p;
for(p=l[x].begin();p!=l[x].end();p++)
if((v=p->first)!=a[x].f&&v!=a[x].son)
dfs2(v,v,p->second);
}
int getlca(int x,int y)
{
while(a[x].top!=a[y].top)
if(a[a[x].top].deep>a[a[y].top].deep)
x=a[a[x].top].f;
else
y=a[a[y].top].f;
if(a[x].deep<a[y].deep)
return x;
return y;
}
int main()
{
freopen("hdu4729.in","r",stdin);
freopen("hdu4729.out","w",stdout);
int t;
scanf("%d",&t);
int tt=0;
while(t--)
{
printf("Case #%d:\n",++tt);
cnt=cnt2=0;
int n,m;
int u,v,c;
int i;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
l[i].clear();
for(i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&c);
l[u].push_back(make_pair(v,c));
l[v].push_back(make_pair(u,c));
}
root[0]=build(0,10000);
dfs1(1,0,1);
dfs2(1,1,0);
for(i=1;i<=m;i++)
{
int s,t,k,c,d;
scanf("%d%d%d%d%d",&s,&t,&k,&c,&d);
int lca=getlca(s,t);
ll flow=find(root[a[s].w],root[a[t].w],root[a[lca].w],0,10000);
if(c<=d)
printf("%I64d\n",flow+k/c);
else
{
ll ans=0;
if(k>=c)
ans=max(ans,flow+(k-c)/d+1);
ans=max(ans,solve(root[a[s].w],root[a[t].w],root[a[lca].w],k/d,0,0,0,10000));
printf("%I64d\n",ans);
}
}
}
return 0;
}