hdu 4729 树链剖分+二分

此题一看就知道是树链剖分,模板题!可怜我模板少抄个字母,在这两百多行的代码里找bug找了三个多小时啊!!!!

解题思路对于要求的x,y点,先可以求得不加任何操作的最大流量Pc1为建造一个路的话费,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;
}
  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

淡定的小Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值