洛谷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) 编辑 收藏 举报