题目大意:有n盏灯和m秒,每盏灯会开a[i]秒然后关a[i]秒然后再开a[i]秒,依次循环,灯打开后,就会产生b[i]的亮度值,问m秒内每一秒最大的亮度值是多少
1<=n,m<=1e5;1<=a[i],b[i]<=1e5
思路:对于一盏灯,它打开的时间段是[1,a[i]]、[2*a[i]+1,3*a[i]]...,对于m的时间内,每盏灯最多有m/a[i]/2个区间,我们对于每一个a[i],只保留一个最大的亮度值,这样最多1e5个a[i],枚举区间的复杂度是O(n*logm),然后用线段树维护最大值时间复杂度O(n*logm*logm)
#include <bits/stdc++.h>
//#include<__msvc_all_public_headers.hpp>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
ll a[N];
ll tree[N * 4], tag[N * 4];
int n, m;
void build(int l, int r, int rt)//构造树状数组
{
tree[rt] = 0;
tag[rt] = 0;//将所有点的标记初始化为0
if (l == r)//已经到了最底部
{
return;
}
int mid = (l + r) >> 1;//将当前区间分成两部分
build(l, mid, rt << 1);//构建左侧的子树
build(mid + 1, r, rt << 1 | 1);//构建右侧的子树
}
void down(int rt, int len)
{//遇到了之前做过标记的点
if (tag[rt])
{
tree[rt << 1] = max(tree[rt << 1], tag[rt]);
tree[rt << 1 | 1] = max(tree[rt << 1 | 1], tag[rt]);//将子节点更新
tag[rt << 1] = max(tag[rt << 1], tag[rt]);
tag[rt << 1 | 1] = max(tag[rt << 1 | 1], tag[rt]);//给两侧的子节点做上同样标记
tag[rt] = 0;
}
}
void add(int a, int b, ll c, int l, int r, int rt)
{//a到b内每一个元素都+c
if (a <= l && b >= r)
{//当前区间已经包含在要查询的区间内
tree[rt] = max(c, tag[rt]);
tag[rt] = max(c, tag[rt]);
return;
}
down(rt, r - l + 1);
int mid = (l + r) >> 1;
if (a <= mid)
{
add(a, b, c, l, mid, rt << 1);
}
if (b > mid)
{
add(a, b, c, mid + 1, r, rt << 1 | 1);
}
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];//回溯时改变父结点的值
}
long long query(int a, int b, int l, int r, int rt)
{
if (a <= l && b >= r)//如果当前的区间在要查询的区间内,就加上这部分结果
return tree[rt];
down(rt, r - l + 1);
int mid = (l + r) >> 1;
ll ans = 0;
if (a <= mid)
ans = max(ans,query(a, b, l, mid, rt << 1));//维护最大值
if (b > mid)
{
ans = max(ans,query(a, b, mid + 1, r, rt << 1 | 1));
}
return ans;
}
void init()
{
for (int i = 1; i <= 100000; i++)
{
a[i] = 0;
}
}
void solve(int t)
{
cin >> n >> m;
init();
for (int i = 1; i <= n; i++)
{
ll x,y;
cin >> x >> y;
a[x] = max(a[x], y);
}
build(1, m, 1);
for (ll i = 1; i <= 100000; i++)
{
if (!a[i])
{
continue;
}
ll now = 1;
while (i * now - i + 1 <= m)
{//枚举所有打开的区间
ll l = i * now - i + 1, r = i * now;
add(l, r, a[i], 1, m, 1);
now += 2;
}
}
cout << "Case #" << t << ": ";
for (int i = 1; i <= m; i++)
{
if (i == m)
{
cout << query(i, i, 1, m, 1);
break;
}
cout << query(i, i, 1, m, 1) << " ";
}
cout << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
int cnt = 0;
while (t--)
{
solve(++cnt);
}
return 0;
}