HDU-4729 树链剖分+主席树

An Easy Problem for Elfness

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 1207    Accepted Submission(s): 249


Problem Description
Pfctgeorge is totally a tall rich and handsome guy. He plans to build a huge water transmission network that covers the whole southwest China. To save the fund, there will be exactly one path between two cities.

Since the water every city provides and costs every day is different, he needs to transfer water from one particular city to another as much as possible in the next few days. However the pipes which connect the cities have a limited capacity for transmission. (Which means the water that transfer though the pipe should not exceed a particular amount) So he has to know the maximum water that the network can transfer in the next few days.

He thought it's a maximum flow problem, so he invites an expert in this field, Elfness (Also known as Xinhang senior sister) to help him figure it out.

Unlike Pfctgeorge, Elfness quickly finds that this problem is much easier than a normal maximum flow problem, and is willing to help Pfctgeorge.

"Oh well, this problem is not a tough one. We can ..."

Abruptly, Pfctgeorge's iPhone rings, and ... the ringtone is Mo Di Da Biao Ke.

"You can make that? Excellent! "Pfctgeorge hangs up his iPhone, and turns to Elfness.

"Here's good news for you. A construction team told me that every pipe's capacity can be extended for one day. And the price for extending one unit capacity varies from day to day. "

"Eh well, that's a good news for you, not me. Now it's rather like a minimum cost ow problem, right? But it's still not a tough one, let me have a think. "

After a few seconds' thought, Elfness comes up with a simple solution.

"Ok, we can solve it like... "

Abruptly, here comes Mo Di Da Biao Ke again.

"Seriously? You can build new pipes? Thank you very much. "

"OK, my dear Elfness, we got more good news. Another construction team said they can build one or more pipes between any two cities and their pipes are exactly like the original ones except that they only work for one day. And the capacity of the new pipes is only one, but they can be extended, too. Of course, their price to build a single pipe also varies in days. "

"You mean the new pipes can be extended too? Wow, things are getting more interesting. Give me a few minutes. "

Elfness takes out his new ultrabook which is awarded in VK cup and does some basic calculation.

"I get it. The problem can be solved ..."

Mo Di Da Biao Ke again, but this time it's from Elfness's phone.

"As you see, I have to go out. But I know someone else who can also solve this; I'll recommend this guy for you. "

And of course, that poor guy is YOU. Help Pfctgeorge solve his problem, and then the favorability about you from Elfness will raise a lot.
 

Input
The first line has a number T (T <= 10) , indicating the number of test cases.

The first line of each test case is two integers N (1 <= N <= 100000) and M (1 <= M <= 100000), indicating the number of the city that the original network connects and the number of days when Pfctgeorge needs to know about the maximum water transmissions. Then next N - 1 lines each describe a pipe that connects two cities. The format will be like U, V , cap (1 <= U, V <= N and 0 <= cap < 10000), which means the ids of the two cities the pipe connects and the transmission limit of the pipe. As is said in description, the network that the cities and pipes form is a tree (an undirected acyclic graph).

Then next M lines of the test case describe the information about the next few days. The format is like  S, T, K, A, B(0 <= K <= 2^31 - 1, 1 <= A, B <= 2^31 - 1). S means the source of the water while T means the sink. K means the total budget in the day. A means the cost for a construction team to build a new pipe and B means the cost for a construction team to extend the capacity of a pipe.

I am glad to list the information of building a new pipe and extending the capacity.

1. Pfctgeorge can build a new pipe between any two cities, no matter they have been directly connected or not. Pfctgeorge can build more than one new pipe between any two cities.
2. The capacity of the pipe that was newly built is  one.
3. Pfctgeorge can extend the capacity of any existed pipe including the newly built one and the original one.
4. Each time you extend the capacity of one pipe, the capacity of that pipe increases one.
5. The cost of building a new pipe is A and the cost of extending a pipe is B.
6. You can take any constructions in any times and the only limit is to make sure the total costs not exceed the budget.
7.  All the work that construction team does only lasts one single day.
 

Output
For every case, you should output "Case #t:" at first, without quotes. The t is the case number starting from 1.
Then for each day, output the maximum water Pfctgeorge can transfer from S and T with a budget of K.
 

Sample Input
  
  
2 5 1 1 2 2 1 3 5 2 4 1 4 5 2 1 5 3 3 2 5 5 1 2 10 2 3 2 3 4 7 2 5 7 1 5 0 1 3 1 3 0 2 3 1 5 3 2 3 1 2 7 3 1 1 3 2 3 1
 

Sample Output
  
  
Case #1: 2 Case #2: 7 2 8 17 4
Hint
In the first sample case, you can extend the capacity of the pipe which connects city2 and city4 by one, or just build a new pipe between city2 and city4.
 

Source

2013 ACM/ICPC Asia Regional Chengdu Online


题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4729


题目大意:

给出一棵带边权的树,m次询问,每次询问有两种操作,加一条单位边花费为A,将某条边流量扩展一单位花费为B,求预算为K的情况下流量的最大值。


解题思路:

首先做一次树链剖分,用RMQ求一下S到T路径上的最小值,然后考虑扩展流量的问题。

对于a<=b的情况,只要在S与T之间建边,然后不断扩展其流量即可。

对于a>b的情况,可以在S与T间建边,最多扩容(k-a)/b+1;也可以在原有路径上扩容,这里二分扩容量,需要用到主席树来统计路径上边权小于该值的边的数量与权值之和。最后取两者中的小者即可。

需要注意在S与T之间建边时需要判断k>=a,另外数据比较弱没有卡int,代码后面附上两组数据供参考。


AC代码:

import java.io.*;
import java.util.*;

public class Main {
	static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static int nextInt() throws IOException    
	{  
	    in.nextToken();    
	    return (int)in.nval;     
	}
	static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
	static int T,n,m,ee,a,b,c,ct,max,k;
	static int ss,tt,pp,aa,bb,sz;
	static long qq,isum,nsum,ans,l,r,mid,res;
	static int[] head=new int[100005];
	static int[] edge=new int[200005];
	static int[] next=new int[200005];
	static int[] cost=new int[200005];
	static int[] fa=new int[100005];
	static int[] id=new int[100005];
	static int[] ww=new int[100005];
	static int[] pos=new int[100005];
	static int[] top=new int[100005];
	static int[] dep=new int[100005];
	static int[] son=new int[100005];
	static int[] size=new int[100005];
	static int[][] min=new int[18][100005];
	static int[] rt=new int[100005];
	static int[] ls=new int[1500005];
	static int[] rs=new int[1500005];
	static int[] cnt=new int[1500005];
	static int[] sum=new int[1500005];
	static void build(int l,int r,int k)
	{
		cnt[k]=0;sum[k]=0;
		if(l==r) return;
		int mid=(l+r)/2;
		ls[k]=++sz;build(l,mid,ls[k]);
		rs[k]=++sz;build(mid+1,r,rs[k]);
	}
	static void updata(int a,int b,int x,int l,int r)
	{
		cnt[a]=cnt[b]+1;
		sum[a]=sum[b]+x;
		if(l==r) return;
		int mid=(l+r)/2;
		if(x<=mid)
		{
			rs[a]=rs[b];ls[a]=++sz;
			updata(ls[a],ls[b],x,l,mid);
		}
		else
		{
			ls[a]=ls[b];rs[a]=++sz;
			updata(rs[a],rs[b],x,mid+1,r);
		}
	}
	static void query(int a,int b,long x,int l,int r)
	{
		if(x>=r)
		{
			nsum+=cnt[b]-cnt[a];
			isum+=sum[b]-sum[a];
			return;
		}
		int mid=(l+r)/2;
		query(ls[a],ls[b],x,l,mid);
		if(x>mid) query(rs[a],rs[b],x,mid+1,r);
	}
	static void init()
	{
		for(int i=1;i<=n;i++)
			min[0][id[i]]=ww[i];
		for(int j=1;(1<<j)<=n;j++)
		for(int i=1;i+(1<<j)-1<=n;i++)
			min[j][i]=Math.min(min[j-1][i],min[j-1][i+(1<<(j-1))]);
	}
	static int min(int l,int r)
	{
		int k=0,res;
		while((1<<(k+1))<r-l+1) k++;
		res=Math.min(min[k][l],min[k][r-(1<<k)+1]);
		return res;
	}
	static void add(int a,int b,int c)
	{
		edge[ee]=b;next[ee]=head[a];
		cost[ee]=c;head[a]=ee++;
	}
	static void dfs(int u,int f,int d)
	{
		size[u]=1;dep[u]=d;
		son[u]=-1;fa[u]=f;
		int v;
		for(int i=head[u];i!=-1;i=next[i])
		{
			v=edge[i];
			if(v==f) continue;
			dfs(v,u,d+1);
			size[u]+=size[v];
			ww[v]=cost[i];
			max=Math.max(max,ww[v]);
			if(son[u]==-1||size[son[u]]<size[v])
				son[u]=v;
		}
	}
	static void dfs2(int u,int f,int t)
	{
		id[u]=++ct;top[u]=t;
		pos[ct]=u;
		if(son[u]!=-1) dfs2(son[u],u,t);
		int v;
		for(int i=head[u];i!=-1;i=next[i])
		{
			v=edge[i];
			if(v==f||v==son[u]) continue;
			dfs2(v,u,v);
		}
	}
	static void prepare()
	{
		max=0;dfs(1,0,1);
		ct=0;dfs2(1,0,1);
		init();sz=0;
		rt[0]=++sz;build(0,max,rt[0]);
		for(int i=1;i<=n;i++)
		{
			rt[i]=++sz;
			updata(rt[i],rt[i-1],ww[pos[i]],0,max);
		}
	}
	static int getmin(int u,int v)
	{
		int ans=10000000;
		while(top[u]!=top[v])
		{
			a=top[u];b=top[v];
			if(dep[a]<dep[b])
			{
				c=u;u=v;v=c;
				c=a;a=b;b=c;
			}
			ans=Math.min(ans,min(id[top[u]],id[u]));
			u=fa[top[u]];
		}
		if(u!=v)
		{
			if(dep[u]>dep[v]) { c=u;u=v;v=c;}
			ans=Math.min(ans,min(id[son[u]],id[v]));
		}
		return ans;
	}
	static long get(int u,int v,long x)
	{
		nsum=isum=0;
		while(top[u]!=top[v])
		{
			a=top[u];b=top[v];
			if(dep[a]<dep[b])
			{
				c=u;u=v;v=c;
				c=a;a=b;b=c;
			}
			query(rt[id[top[u]]-1],rt[id[u]],x,0,max);
			u=fa[top[u]];
		}
		if(u!=v)
		{
			if(dep[u]>dep[v]) { c=u;u=v;v=c;}
			query(rt[id[son[u]]-1],rt[id[v]],x,0,max);
		}
		long res=nsum*x-isum;
		return res;
	}

	public static void main(String[] args) throws IOException {
		//Scanner in=new Scanner(System.in);
		T=nextInt();
		for(int t=1;t<=T;t++)
		{
			n=nextInt();m=nextInt();
			Arrays.fill(head,-1);ee=0;
			for(int i=1;i<n;i++)
			{
				a=nextInt();b=nextInt();
				c=nextInt();
				add(a,b,c);add(b,a,c);
			}
			prepare();
			out.println("Case #"+t+":");
			while(m-->0)
			{
				ss=nextInt();tt=nextInt();
				k=nextInt();
				aa=nextInt();bb=nextInt();
				pp=getmin(ss,tt);
				if(aa<=bb) ans=(long)pp+k/aa;
				else
				{
					ans=(k>=aa)?(k-aa)/bb+1:0;
					k/=bb;
					l=1;r=k;res=0;
					while(l<=r)
					{
						mid=l+(r-l)/2;
						qq=get(ss,tt,pp+mid);
						if(qq<=k) { res=mid;l=mid+1;}
						else r=mid-1;
					}
					ans=Math.max(ans,res)+pp;
				}
				out.println(ans);
			}
		}
		out.flush();
	}
}
/* 
2
2 1
1 2 4
2 1 2 4 3
2 1
1 2 4
2 1 2147483647 2 1
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值