1. 程式人生 > >codefoces730C Bulmart 二分答案+貪心check && 堆維護

codefoces730C Bulmart 二分答案+貪心check && 堆維護

C. Bulmart time limit per test 1.5 seconds memory limit per test 512 megabytes input standard input output standard output

A new trade empire is rising in Berland. Bulmart, an emerging trade giant, decided to dominate the market of ... shovels! And now almost every city in Berland has a Bulmart store, and some cities even have several of them! The only problem is, at the moment sales are ... let's say a little below estimates. Some people even say that shovels retail market is too small for such a big company to make a profit. But the company management believes in the future of that market and seeks new ways to increase income.

There are n cities in Berland connected with m bi-directional roads. All roads have equal lengths. It can happen that it is impossible to reach a city from another city using only roads. There is no road which connects a city to itself. Any pair of cities can be connected by at most one road.

There are w

 Bulmart stores in Berland. Each of them is described by three numbers:

  • ci — the number of city where the i-th store is located (a city can have no stores at all or have several of them),
  • ki — the number of shovels in the i-th store,
  • pi — the price of a single shovel in the i-th store (in burles).

The latest idea of the Bulmart management is to create a program which will help customers get shovels as fast as possible for affordable budget. Formally, the program has to find the minimum amount of time needed to deliver rj shovels to the customer in the city gj for the total cost of no more than aj burles. The delivery time between any two adjacent cities is equal to 1. If shovels are delivered from several cities, the delivery time is equal to the arrival time of the last package. The delivery itself is free of charge.

The program needs to find answers to q such queries. Each query has to be processed independently from others, i.e. a query does not change number of shovels in stores for the next queries.

Input

The first line contains two integers nm (1 ≤ n ≤ 50000 ≤ m ≤ min(5000, n·(n - 1) / 2)). Each of the next m lines contains two integers xe and ye, meaning that the e-th road connects cities xe and ye (1 ≤ xe, ye ≤ n).

The next line contains a single integer w (1 ≤ w ≤ 5000) — the total number of Bulmart stores in Berland. Each of the next w lines contains three integers describing the i-th store: ci, ki, pi (1 ≤ ci ≤ n, 1 ≤ ki, pi ≤ 2·105).

The next line contains a single integer q (1 ≤ q ≤ 1000) — the number of queries. Each of the next q lines contains three integers describing the j-th query: gj, rj and aj (1 ≤ gj ≤ n1 ≤ rj, aj ≤ 109)

Output

Output q lines. On the j-th line, print an answer for the j-th query — the minimum amount of time needed to deliver rj shovels to the customer in city gj spending no more than aj burles. Print -1 if there is no solution for the j-th query.

Example input
6 4
4 2
5 4
1 2
3 2
2
4 1 2
3 2 3
6
1 2 6
2 3 7
3 1 2
4 3 8
5 2 5
6 1 10
output
2
-1
2
2
3
-1
題解:這道題目我們想了兩種解法:

第一種,也是比較好寫的演算法,就是把所有的商店按照商品價格從小到大排序。並對於每個詢問,從起點開始跑一遍bfs,得到每個商店的距離。

再二分答案,在check函式裡這麼寫,依據價格從小到大遍歷商店,貪心的選取合適數量的商品。如果最後能取到r個商品並且剩餘的錢數>=0,說明本次check是可行的。

這個演算法非常好想,也好寫。

第二種,這種演算法不太好想,也不太好寫。

我們需要r個商品,那麼我們可以從g點bfs的過程中,維護一個可以容納商品數量為r的堆,每次bfs到一個新的地點的時候,我們都把這個地點所有的商店裡的商品跟堆頂商品進行比較,然後更新這個堆。(這個堆維護的是到目前為止,價格前r小的r個商品)

這樣的話,每到一個點,我們都判斷一下當前堆中的商品價格總和是否小於等於我們帶的現金a,如果是那麼就可以直接輸出答案了。答案即是當前這個點到起點的距離。

程式碼1,二分版本:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 1e5;
const int INF = 1e5;
int head[MAXN];
int dis[MAXN];
int vis[MAXN];
int cnt;
struct edge{ 
    int v; 
    int next; 
    int cost; 
}Es[MAXN<<1];  
void init(){ 
    cnt = 0; 
    memset(head,-1,sizeof(head)); 
}
inline void add_edge(int i,int j,int cost){   
    Es[cnt].v = j; 
    Es[cnt].cost = cost; 
    Es[cnt].next = head[i]; 
    head[i] = cnt++; 
}   
struct shop{
	int id,num,price;
	friend bool operator<(shop sp1,shop sp2){
		return sp1.price < sp2.price;
	}
};
int n,m,q,snum;
vector<shop> shops;
bool check(int x,int knum,int cash){
	
	for(int i = 0;i < shops.size();++i){
		shop sp = shops[i];
		if(dis[sp.id] > x) continue;
		int k = min(knum,sp.num);
		knum -= k;
		cash -= k * sp.price;
		if(!knum) break;
	}
	if(!knum && cash >= 0) return true;
	return false;
}
void bfs(int s){
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	queue<int> Q;
	dis[s] = 0;
	vis[s] = 1;
	Q.push(s);
	while(!Q.empty()){
		int u = Q.front();Q.pop();
		for(int e = head[u];e != -1;e = Es[e].next){
			int v = Es[e].v; 
			if(!vis[v]){
				dis[v] = dis[u] + 1;
				vis[v] = 1;
				Q.push(v);
			}
		}
	}
	
}
main(){
	init();
	scanf("%lld%lld",&n,&m);
	for(int i = 1;i <= m;++i){
		int a,b;
		scanf("%lld%lld",&a,&b);
		add_edge(a,b,1);
		add_edge(b,a,1);
	}
	scanf("%lld",&snum);
	for(int i = 0;i < snum;i++){
		int id,price,num;
		scanf("%lld%lld%lld",&id,&num,&price);
		shops.push_back((shop){id,num,price});
	}
	sort(shops.begin(),shops.end());
	scanf("%lld",&q);
	while(q--){
		int src,knum,cash;
		scanf("%lld%lld%lld",&src,&knum,&cash);
		bfs(src);
		int sl = 0,sr = INF;
		while(sr - sl > 1){
			int mid  = (sl + sr) >> 1;
			if(check(mid,knum,cash)) sr = mid;
			else sl = mid;
		}
		if(check(sl,knum,cash)) printf("%lld\n",sl);
		else if(check(sr,knum,cash)) printf("%lld\n",sr);
		else printf("%lld\n",-1LL);
	}
	return 0;
}

程式碼2,維護小頂堆版:
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
const int MAXN = 5005;
int head[MAXN],vis[MAXN];
int dis[MAXN];
int cnt;
struct edge{ 
    int v; 
    int next; 
    int cost; 
}Es[10007];  
struct node{
	int dis,val,num;
	friend bool operator<(node n1,node n2){// choose the max
		return n1.val < n2.val;
	}
};
priority_queue<node> heap;
vector<pii> shops[MAXN];
void init(){ 
    cnt = 0; 
    memset(head,-1,sizeof(head)); 
}
inline void add_edge(int i,int j,int cost){   
    Es[cnt].v = j; 
    Es[cnt].cost = cost; 
    Es[cnt].next = head[i]; 
    head[i] = cnt++; 
}   
int bfs(int s,int items,int cash){
	memset(dis,0,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue<int> Q;
	Q.push(s);
	dis[s] = 0;
	vis[s] = 1;
	int heap_num = 0;
	int heap_cost = 0;
	while(!Q.empty())
	{
		int u = Q.front();Q.pop();
		for(int i = 0;i < shops[u].size();i++){
			pii p = shops[u][i];
			int tmp_price = p.first;
			int tmp_num = p.second;
			int f = 1;
			while(f && tmp_num){
				f = 0;
				int remain = items - heap_num;
				if(remain > 0){
					heap.push((node){dis[u],tmp_price,min(tmp_num,remain)});
					int kkk = min(tmp_num,remain);
					heap_num += kkk;
					heap_cost += kkk * tmp_price;
					tmp_num -= kkk;
					f = 1;
				}
				else if(remain == 0){
					node td = heap.top();
					while(tmp_num && td.val > tmp_price){
						heap.pop();
						f = 1;
						int kkk = min(td.num,tmp_num);
						heap_cost += kkk * (tmp_price - td.val);
						td.num -= kkk;
						tmp_num -= kkk;
						if(td.num) heap.push(td);
						heap.push((node){dis[u],tmp_price,kkk});
						td = heap.top();
					}
				}
			}
		}
		if(heap_num >= items && heap_cost <= cash){
			int ans = 0;
			while(!heap.empty()){
				node p = heap.top();heap.pop();
				if(p.num > 0){
					ans = max(ans,p.dis);
				}
			}
			return ans;
		}
		for(int e = head[u];e != -1;e = Es[e].next){
			int v = Es[e].v;
			if(vis[v]) continue;
			dis[v] = dis[u] + 1;
			vis[v] = 1;
			Q.push(v);
			
		}
		
	}	
	return -1;
	
}
int n,m,q;
main(){
	init();
	scanf("%lld%lld",&n,&m);
	for(int i = 1;i <= m;i++){
		int a,b;
		scanf("%lld%lld",&a,&b);
		add_edge(a,b,1);
		add_edge(b,a,1);
	}
	int shop = 0;
	scanf("%lld",&shop);
	for(int i = 1;i <= shop;i++){
		int ver;
		int num,cost;
		scanf("%lld%lld%lld",&ver,&num,&cost);
		shops[ver].push_back(make_pair(cost,num));
	}
	for(int i = 1;i <= n;i++) sort(shops[i].begin(),shops[i].end());
	scanf("%lld",&q);
	while(q--){
		int g,r,a;
		scanf("%lld%lld%lld",&g,&r,&a);
		while(!heap.empty()){
			heap.pop();
		}
		cout<<bfs(g,r,a)<<endl;
	}
	return 0;
}