思路:这个树链剖分其实还是比较明显的。将边按权值排序后插入线段树,然后用线段树查找区间中比某个数小的数和,以及这样的数的个数。当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; }