您的位置:首页 > 其它

【树链剖分】 HDU 4729 An Easy Problem for Elfness 二分

2015-09-03 21:32 375 查看
点击打开链接

给出一棵树 每条边有容量

新建一条边(初始值为1) 需要A$ 

容量增加1 需要B$

询问  预算有K 使得S->T的流量最大

分三种情况

1. A<=B时  为S->T路径上最小值+K/A;

2. A > B时 新建一条边再扩容该条边  

3. 扩容 S->T路径上的边 使得最小值最大

1和2可以很快的算出

对于第3种情况我们可以二分答案 求解

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <deque>
#include <set>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
typedef long long LL;
const int MAXN = 101000;//点数的最大值
const int MAXM = 604000;//边数的最大值
const LL INF = 1152921504;
const LL mod= 258280327;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int read()
{
char ch=' ';
int ans=0;
while(ch<'0' || ch>'9')
ch=getchar();
while(ch<='9' && ch>='0')
{
ans=ans*10+ch-'0';
ch=getchar();
}
return ans;
}
struct EDGENODE{
int to;
int w;
int next;
}edges[MAXM];
int head[MAXN],edge;
inline void init(){
edge=0;
memset(head,-1,sizeof(head));
}
inline void addedge(int u,int v,int w){
edges[edge].w=w,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
edges[edge].w=w,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++;
}
int que[MAXN]; // 队列
bool vis[MAXN]; // 访问标记
int son[MAXN]; // 重儿子
int idx[MAXN]; // 结点v在其路径中的编号
int dep[MAXN]; // 结点v的深度
int siz[MAXN]; // 以结点v为根的子树的结点个数
int belong[MAXN]; // 结点v所属的路径编号
int fa[MAXN]; // 结点v的父亲结点
int top[MAXN]; // 编号为p的路径的顶端结点
int len[MAXN]; // 路径p的长度
int sump[MAXN]; // 路径p的编号
int seg[MAXN]; // 结点v的父边在线段树中的位置
int wei[MAXN]; // 结点v的父边的权值
int l,r,ans,cnt;
int n;
char cmd[22];
int num[MAXN];
void split(){
memset(dep,-1,sizeof(dep));
l=0;
dep[ que[r=1]=1 ]=0; // 将根结点插入队列,并设深度为0
fa[1]=-1; // 默认 1 为根结点
wei[1]=0;
while (l<r){ // 第一遍搜索求出 fa,dep,wei
int u=que[++l];
vis[u]=false; // 顺便初始化vis
for (int i=head[u];i!=-1;i=edges[i].next){
int v=edges[i].to;
int w=edges[i].w;
if (dep[v]==-1){ // 未访问过的结点
dep[ que[++r]=v ]=dep[u]+1; // 将v插入队列并设深度为dep[u]+1
fa[v]=u; // v的父结点为u
wei[v]=w; // v的父边权值
}
}
}
cnt=0; // 重链编号
for (int i=n;i>0;i--){
int u=que[i],p=-1;
siz[u]=1;
son[u]=p;
for (int k=head[u];k!=-1;k=edges[k].next){
int v=edges[k].to;
if (vis[v]){ // 若v是u的子结点
siz[u]+=siz[v]; // 计数
if (p==-1||siz[v]>siz[p]){
son[u]=v;
p=v; // u的重儿子是v
}
}
}
if (p==-1){ // u是叶子结点
idx[u]=len[++cnt]=1; // 一个新的路径编号为cnt,u是路径中的第一个结点
belong[ top[cnt]=u ]=cnt; // u是顶端结点,且u属于路径cnt
}
else{ // u不是叶子结点
idx[u]=++len[ belong[u]=belong[p] ]; // u属于重儿子所在的链,链长+1,u是路径中第len个结点
top[ belong[u] ]=u; // u是顶端结点
}
vis[u]=true; // 访问标记
}
}
struct tree
{
LL sum[MAXN<<2];
LL have;
void pushup(int rt)
{
sum[rt]=min(sum[rt<<1],sum[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=num[l];
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
LL query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
return sum[rt];
}
int m=(l+r)>>1;
LL ans=INF;
if(L<=m)
ans=min(ans,query(L,R,lson));
if(R>m)
ans=min(ans,query(L,R,rson));
return ans;
}
bool yes(LL val,int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R&&sum[rt]>=val)
return true;
if(l==r)
{
if(sum[rt]>=val)
return true;
have-=(val-sum[rt]);
if(have>=0)
return true;
else
return false;
}
int m=(l+r)>>1;
bool g1=true,g2=true;
if(L<=m)
g1=yes(val,L,R,lson);
if(m<R)
g2=yes(val,L,R,rson);
return g1&&g2;
}
}xixixi;
LL find(int va,int vb){
int f1=top[belong[va]],f2=top[belong[vb]];
LL tmp=INF;
while (f1!=f2){
if (dep[f1]<dep[f2]){
swap(f1,f2);
swap(va,vb);
}
tmp=min(tmp,xixixi.query(seg[f1],seg[va],1,n,1));
va=fa[f1];
f1=top[belong[va]];
}
if (va==vb) return tmp;
if (dep[va]>dep[vb]) swap(va,vb);
return min(tmp,xixixi.query(seg[son[va]],seg[vb],1,n,1));
}
bool gao(LL x,int va,int vb)
{
int f1=top[belong[va]],f2=top[belong[vb]];
while (f1!=f2){
if (dep[f1]<dep[f2]){
swap(f1,f2);
swap(va,vb);
}
if(!xixixi.yes(x,seg[f1],seg[va],1,n,1))
return false;
va=fa[f1];
f1=top[belong[va]];
}
if (va==vb) return true;
if (dep[va]>dep[vb]) swap(va,vb);
if(!xixixi.yes(x,seg[son[va]],seg[vb],1,n,1))
return false;
return true;

}
int main()
{
int m,cas=0;
int t;
scanf("%d",&t);
while (t--)
{
cin>>n>>m;
init();
int x,y,a,b,k,c;
for (int i=1;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
// a=read(),b=read(),c=read();
addedge(a,b,c);
}
split();
sump[0]=0;
for (int i=1;i<=cnt;i++) sump[i]=sump[i-1]+len[i];
for (int i=1;i<=n;i++){
seg[i]=sump[ belong[i] ]-idx[i]+1;
num[ seg[i] ]=wei[i];
}
xixixi.build(1,n,1);
printf("Case #%d:\n",++cas);
while (m--)
{
// x=read(),y=read(),k=read(),a=read(),b=read();
scanf("%d%d%d%d%d",&x,&y,&k,&a,&b);
LL ans=find(x,y);
if(a<=b)
printf("%I64d\n",ans+k/a);
else
{
LL now=(LL)k/b,hh=ans,out=0;
if(k>=a)
hh=ans+(k-a)/b+1;
LL ll=hh,rr=max(hh,ans+now);
while(ll<=rr)
{
LL mm=(ll+rr)>>1;
xixixi.have=now;
if(gao(mm,x,y))
{
out=mm;
ll=mm+1;
}
else rr=mm-1;
}
printf("%I64d\n",max(hh,out));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: