CF 589G 樹狀數組

題目鏈接:http://codeforces.com/contest/589/problem/G


好久沒做過樹狀數組的了,也應該開始練練數據結構了

題意:給你m個工作日,每個工作日有工作時間,給你n個員工,每個員工每天工作有準備工作時間和實際工作時間,每天實際工作時間之前必須做完準備工作時間,問這個員工最早要第幾天完成

思路:一開始的想法只想到把員工的準備工作時間從小到大排序,其他的想法還真沒有。。。後來想到了可以弄一個隊列,再弄一個樹狀數組,表示第1到第i天的所有的工作時間的和,因爲員工的準備工作時間已經從小到大排序了,所以每次只要把隊列中小於該員工準備工作時間的工作時間刪去,在樹狀數組中更新就好了。之後在二分工作日,假設當前列舉到第mid天,那麼知道了1到mid天的所有時間和,但是這個時間和是所有的時間和,應該還有減去準備時間 * 天數的纔是真正的工作時間,所以還要再弄一個樹狀數組記錄1到mid天有幾天被刪去了,這樣就能計算出1到mid天有幾天是實際工作的。


#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn = 200005;

ll sum[maxn];
int _sum[maxn];
ll ans[maxn];
struct ppp
{
	int id,pre,v;
	void read(int _id){
		scanf("%d%d",&pre,&v);
		id = _id;
	}
	bool operator < (const ppp & nex)const{
		return pre < nex.pre;
	}
}ori[maxn];
vector<int> vec[maxn * 5];
int n,m;
int lowbit(int x)
{
	return x & -x;
}
void sub(int x,int v)
{
	while(x <= m)
	{
		sum[x] -= v;
		x += lowbit(x);
	}
}
ll query(int x)
{
	ll ans = 0;
	while(x > 0)
	{
		ans += sum[x];
		x -= lowbit(x);
	}
	return ans;
}
void _add(int x)
{
	while(x <= m)
	{
		_sum[x] += 1;
		x += lowbit(x);
	}
}
int _query(int x)
{
	int ans = 0;
	while(x > 0)
	{
		ans += _sum[x];
		x -= lowbit(x);
	}
	return ans;
}
int cal(int i)
{
	int l = 1, r = m;
	int ret = 0;
	while(l <= r)
	{
		int mid = (l + r) >> 1;
		int cnt = mid - _query(mid);
		ll temp = query(mid) - ori[i].pre * 1LL * cnt;
		if(temp >= ori[i].v){
			r = mid - 1;
			ret = mid;
		}
		else l = mid + 1;
	}
	return ret;
}

void init()
{
	int pos = 0;
	mem(sum,0);
	mem(_sum,0);
	for(int i = 0;i < maxn * 5;i ++)vec[i].clear();
	for(int i = 1,a;i <= m;i++){
		scanf("%d",&a);
		int x = i;
		while(x <= m){
			sum[x] += a;
			x += lowbit(x);
		}
		vec[a].push_back(i);
	}
	for(int i = 1;i <= n;i++)ori[i].read(i);
	sort(ori + 1,ori + 1 + n);
	for(int i = 1;i <= n;i++){
		while(pos <= ori[i].pre){
			for(int j = 0;j < vec[pos].size();j++)
			{
				sub(vec[pos][j],pos);
				_add(vec[pos][j]);
			}
			pos++;
		}
		ans[ori[i].id] = cal(i);
	}
}
int main()
{
	while(cin>>n>>m)
	{
		init();
		for(int i = 1;i <= n;i++)
			cout<<ans[i]<<" ";
		cout<<endl;
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章