此题一看就知道是树链剖分,模板题!可怜我模板少抄个字母,在这两百多行的代码里找bug找了三个多小时啊!!!!
解题思路:对于要求的x,y点,先可以求得不加任何操作的最大流量P,c1为建造一个路的话费,c2为增加一个容量的花费,如果c1<=c2,那么结果就为P+k/c1。
否则,如果先建一条路,那么最大的流量是M=P+1+(k-c1)/c2,如果不新建路只加边呢?那就可以二分求得最大的结果,为了节省时间,可以对整体进行最小值为M的二分结果。
下面是我的代码,不是很简单,但是各个函数还算清晰了。。。。
#pragma comment(linker,"/STACK:124000000,124000000")
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<climits>
#include<map>
using namespace std;
#define rep(i,n) for(int i=0; i<n; i++)
#define repf(i,n,m) for(int i=(n); i<=(m); ++i)
#define repd(i,n,m) for(int i=(n); i>=(m); --i)
#define ll __int64
#define arc(a) ((a)*(a))
#define inf 100000
#define exp 0.000001
#define N 200005
class match{
public:
int n,m,len,topw;
int fa[N],size[N],son[N],w[N],top[N],dep[N];
int pre[N],lit[N];
int value[N];
int p[N];
int cont;
struct node{ int y,pre,v;};
node a[N];
struct no{int l,r,Min;};
no aa[N*4];
void init()
{
len=0; topw=1;value[1]=0;
memset(pre,-1,sizeof(pre));
memset(son,-1,sizeof(son));
}
void addpage(int x,int y,int z)
{
a[len].pre=pre[x];
a[len].v=z;
a[len].y=y;
pre[x]=len++;
}
void dfs(int s,int faa,int h)
{
dep[s]=h;
size[s]=1;
int Max=0,sign;
for(int i=pre[s]; i!=-1; i=a[i].pre)
{
int y=a[i].y;
if(y==faa) continue;
fa[y]=s;
value[y]=a[i].v;//jilu shangyi ge
dfs(y,s,h+1);
if(size[y]>Max) Max=size[y],sign=y;
size[s]+=size[y];
}
if(Max!=0) son[s]=sign;
}
void dfs2(int s,int faa,int tp)
{
p[topw]=s;
w[s]=topw++; top[s]=tp;
if(son[s]!=-1) dfs2(son[s],s,tp);
for(int i=pre[s]; i!=-1; i=a[i].pre)
{
int y=a[i].y;
if(y==faa || y==son[s]) continue;
dfs2(y,s,y);
}
lit[s]=topw-1;
}
void bulidtree(int s,int l,int r)
{
aa[s].l=l, aa[s].r=r;
if(l==r)
{
aa[s].Min=value[p[l]];
return;
}
int mid=(l+r)/2;
bulidtree(2*s,l,mid);
bulidtree(2*s+1,mid+1,r);
aa[s].Min=min(aa[2*s].Min,aa[2*s+1].Min);
}
int refresh(int s,int l,int r)
{
if(aa[s].l>=l && aa[s].r<=r)
return aa[s].Min;
int mid=(aa[s].l+aa[s].r)/2;
if(r<=mid)
return refresh(2*s,l,r);
else if(l>mid)
return refresh(2*s+1,l,r);
else return min(refresh(2*s,l,r),refresh(2*s+1,l,r));
}
int deal(int s,int x,int y)
{
int fx=top[x],fy=top[y];
int Min=INT_MAX;
while(fx!=fy)
{
if(dep[fx]>dep[fy])
swap(fx,fy),swap(x,y);
Min=min(Min,refresh(1,w[fy],w[y]));
y=fa[fy],fy=top[y];
}
if(dep[x]>dep[y])
swap(x,y);
if(x!=y)
Min=min(Min,refresh(1,w[x]+1,w[y]));
if(Min==INT_MAX)
Min=9999;
return Min;
}
bool True(int s,int l,int r,ll mid)
{
// cout<<s<<" "<<l<<" "<<r<<" "<<mid<<" "<<cont<<endl;
if(aa[s].l>=l && aa[s].r<=r && aa[s].Min>=mid)
return true;
if(aa[s].l==aa[s].r)
{
if(aa[s].Min>=mid) return true;
cont-=(mid-aa[s].Min);
if(cont<0) return false;
return true;
}
int mi=(aa[s].l+aa[s].r)/2;
if(r<=mi) return True(2*s,l,r,mid);
else if(l>mi) return True(2*s+1,l,r,mid);
if(True(2*s,l,r,mid) && True(2*s+1,l,r,mid))
return true;
return false;
}
bool fun(int s,int x,int y,ll mid)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(dep[fx]>dep[fy])
swap(fx,fy),swap(x,y);
if(!True(1,w[fy],w[y],mid))
return false;
y=fa[fy]; fy=top[y];
}
if(dep[x]>dep[y]) swap(x,y);
if(x!=y)
if(!True(1,w[x]+1,w[y],mid))
return false;
return true;
}
};
match sa;
int n,m;
int main()
{
// freopen("in","r",stdin);
int test;
scanf("%d",&test);
repf(ror,1,test)
{
scanf("%d%d",&n,&m);
sa.n=n;
sa.init();
int x,y,z,k,c1,c2;
rep(i,n-1)
{
scanf("%d%d%d",&x,&y,&z);
sa.addpage(x,y,z);
sa.addpage(y,x,z);
}
sa.dfs(1,-1,1);
sa.dfs2(1,-1,1);
sa.bulidtree(1,1,n);
printf("Case #%d:\n",ror);
repf(i,1,m)
{
scanf("%d%d%d%d%d",&x,&y,&k,&c1,&c2);
ll rr=sa.deal(1,x,y);
ll an=rr+k/c1;
ll ans;
if(c1<=c2)
ans=an;
else
{
if(k>=c1) an=max(an,rr+1+(k-c1)/c2);
ll l=an,r=10000+max(k/c2,k/c1);
ans=an;
int cont=k/c2;
sa.cont=cont;
while(l<=r)
{
ll mid=(l+r)/2;
sa.cont=cont;
if(sa.fun(1,x,y,mid))
ans=mid,l=mid+1;
else r=mid-1;
}
}
printf("%I64d\n",ans);
// cout<<ans<<endl;
}
}
return 0;
}