一名苦逼的OIer,想成为ACMer

Iowa_Battleship

洛谷1083 借教室

原题链接

二分+差分

运用差分的思想,对于在\([l, r]\)间租借\(x\)间教室的订单,在差分数组(设为\(a[]\))中只需将\(a[l] + x, a[r + 1] - x\)即可,最后只需要前缀和一下就可以计算出某一天需要租借的教室数量,再与当天可租借的教室数量比较大小就可以知道是否可行。
于是我们成功将修改并判断所需复杂度降为线性,再套上一个二分答案即可。
时间复杂度\(O((n + m) \log m)\)

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;
struct ord {
	int x, y, nd;
};
ord a[N];
int res[N], b[N], n;
inline int re()
{
	int x = 0;
	char c = getchar();
	bool p = 0;
	for (; c < '0' || c > '9'; c = getchar())
		p |= c == '-';
	for (; c >= '0' && c <= '9'; c = getchar())
		x = x * 10 + c - '0';
	return p ? -x : x;
}
bool judge(int mid)
{
	int i;
	memset(b, 0, sizeof(b));
	for (i = 1; i <= mid; i++)
		b[a[i].x] += a[i].nd, b[a[i].y + 1] -= a[i].nd;
	for (i = 1; i <= n; i++)
	{
		b[i] += b[i - 1];
		if (b[i] > res[i])
			return true;
	}
	return false;
}
int main()
{
	int i, m, l = 1, r, mid, ans = 0;
	n = re(); r = m = re();
	for (i = 1; i <= n; i++)
		res[i] = re();
	for (i = 1; i <= m; i++)
		a[i].nd = re(), a[i].x = re(), a[i].y = re();
	while (l <= r)
	{
		mid = (l + r) >> 1;
		if (judge(mid))
		{
			ans = mid;
			r = mid - 1;
		}
		else
			l = mid + 1;
	}
	if (!ans)
		return printf("0"), 0;
	printf("-1\n%d", ans);
	return 0;
}

线段树

这题用线段树也可以很方便的求解。
以能出租的教室建立线段树,维护一个\(\min\),修改自然就是区间减。
当整个区间的最小值(即线段树根上储存的最小值)小于\(0\)时,就说明已经无法满足订单的要求了。
时间复杂度\(O(m\log n)\),但因为线段树常数还是比较大的,写的丑可能就跑不过去了。

#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e6 + 10;
int res[N], mi[N << 2], us[N << 2];
inline int re()
{
	int x = 0;
	char c = getchar();
	bool p = 0;
	for (; c < '0' || c > '9'; c = getchar())
		p |= c == '-';
	for (; c >= '0' && c <= '9'; c = getchar())
		x = x * 10 + c - '0';
	return p ? -x : x;
}
inline int minn(int x, int y) { return x < y ? x : y; }
void pp(int r) { mi[r] = minn(mi[r << 1], mi[r << 1 | 1]); }
void pn(int r)
{
	int &k = us[r];
	if (k)
	{
		int lx = r << 1, ly = r << 1 | 1;
		us[lx] += k; us[ly] += k;
		mi[lx] += k; mi[ly] += k;
		k = 0;
	}
}
void bu(int r, int x, int y)
{
	if (!(x ^ y))
		mi[r] = res[x];
	else
	{
		int mid = (x + y) >> 1;
		bu(r << 1, x, mid);
		bu(r << 1 | 1, mid + 1, y);
		pp(r);
	}
}
void mdf(int r, int x, int y, int ql, int qr, int k)
{
	if (ql <= x && y <= qr)
	{
		mi[r] += k; us[r] += k;
		return;
	}
	int mid = (x + y) >> 1;
	pn(r);
	if (ql <= mid)
		mdf(r << 1, x, mid, ql, qr, k);
	if (mid < qr)
		mdf(r << 1 | 1, mid + 1, y, ql, qr, k);
	pp(r);
}
int main()
{
	int i, n, m, x, y, z;
	n = re(); m = re();
	for (i = 1; i <= n; i++)
		res[i] = re();
	bu(1, 1, n);
	for (i = 1; i <= m; i++)
	{
		z = re(); x = re(); y = re();
		mdf(1, 1, n, x, y, -z);
		if (mi[1] < 0)
			return printf("-1\n%d", i), 0;
	}
	printf("0");
	return 0;
}

posted on 2019-03-01 19:59  Iowa_Battleship  阅读(189)  评论(0编辑  收藏  举报

导航