题目链接:http://codeforces.com/gym/102822/problem/J
题意:有n个灯,灯有亮度值x和亮的时间t,每2k*t+1到(2k+1)*t时间内灯亮,(2k+1)*t+1到(2k+2)*t时间内灯熄灭,问m个时间点内每个时间点灯的最大亮度。
解题思路:
区间修改(区间求最大值)+单点查询
①利用线段树,区间修改+单点查询,注意改一下模版,每次不是求和,而是求最大值了。
同时注意按Lamb[i].t进行排序,相同的t将亮度x大的放在前面,如果 Lamb[i].t已经处理过,直接跳过来去重
②利用并查集取最大覆盖区域,首先将Lamb按照亮度x由大到小进行排序,可以知道如果i这个时间点已经处理过,有了亮度值,那么就一定是最大亮度,不需要处理,所以可以使用并查集每次处理时直接跳过已经处理过的区域。
同时也要注意去重,将已经处理过的t去掉,不然会t
思路①:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
using namespace std;
const int MAXN = 1e5 + 5;
int sum[MAXN << 2], add[MAXN << 2];
struct lamb {
int t;
int x;
}Lamb[MAXN];
struct Node {
int l, r;
int mid() { return (l + r) >> 1; }
} tree[MAXN << 2];
void PushDown(int rt, int x) {
if (add[rt]) {
add[rt << 1] = max(add[rt<<1] , add[rt]);
add[rt << 1 | 1] = max(add[rt << 1 | 1], add[rt]);
sum[rt << 1] = max(add[rt], sum[rt << 1]);
sum[rt << 1 | 1] = max(add[rt], sum[rt << 1 | 1]);
add[rt] = 0;
}
}
void build(int l, int r, int rt) {
tree[rt].l = l;
tree[rt].r = r;
add[rt] = 0;
if (l == r) {
sum[rt] = 0;
return;
}
int mid = tree[rt].mid();
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
sum[rt] = max(sum[rt << 1],sum[rt << 1 | 1]);
}
void update(int c, int l, int r, int rt) {
if (tree[rt].l == l && r == tree[rt].r) {
add[rt] = max(add[rt],c);
sum[rt] = max(sum[rt], c);
return;
}
if (tree[rt].l == tree[rt].r)
return;
PushDown(rt, tree[rt].r - tree[rt].l + 1);
int mm = tree[rt].mid();
if (r <= mm) update(c, l, r, rt << 1);
else if (l > mm) update(c, l, r, rt << 1 | 1);
else {
update(c, l, mm, rt << 1);
update(c, mm + 1, r, rt << 1 | 1);
}
sum[rt] = max(sum[rt << 1],sum[rt << 1 | 1]);
}
int query(int l, int r, int rt) {
if (l == tree[rt].l && r == tree[rt].r) {
return sum[rt];
}
PushDown(rt, tree[rt].r - tree[rt].l + 1);
int m = tree[rt].mid();
int res = 0;
if (r <= m) res = max(res,query(l, r, rt << 1));
else if (l > m) res = max(res,query(l, r, rt << 1 | 1));
else {
res = max(res,query(l, m, rt << 1));
res = max(res,query(m + 1, r, rt << 1 | 1));
}
return res;
}
bool cmp(lamb a, lamb b) {
return a.t==b.t ? a.x>b.x:a.t < b.t;
}
int t;
int n, m;
int vis[MAXN];
void init() {
memset(vis, 0, sizeof(vis));
memset(tree, 0, sizeof(tree));
memset(sum, 0, sizeof(sum));
memset(add, 0, sizeof(add));
}
int main() {
cin >> t;
int cas = 0;
while (t--) {
init();
cin >> n >> m;
build(1, m, 1);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &Lamb[i].t, &Lamb[i].x);
}
sort(Lamb + 1, Lamb + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
if (vis[Lamb[i].t])
continue;
int cur = 0;
while (cur * Lamb[i].t + 1 <= m) {
int val = min(m, (cur + 1) * Lamb[i].t);
update(Lamb[i].x, cur * Lamb[i].t + 1, val, 1);
cur += 2;
}
vis[Lamb[i].t] = 1;
}
cout << "Case #" << ++cas << ": ";
for (int i = 1; i <= m; i++) {
printf("%d",query(i, i, 1));
if (i == m)
printf("\n");
else
printf(" ");
}
}
return 0;
}
思路②:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
using namespace std;
const int MAXN = 1e5 + 5;
int pa[MAXN];
int ans[MAXN];
int vis[MAXN];
int t, n, m;
struct node {
int t;
int x;
}Lamb[MAXN];
int find(int x) {
return x == pa[x] ? x : pa[x] = find(pa[x]);
}
bool cmp(node a, node b) {
return a.x == b.x ? a.t > b.t : a.x > b.x;
}
int main() {
cin >> t;
int cas = 1;
while (t--) {
memset(vis, 0, sizeof(vis));
cin >> n >> m;
for (int i = 1; i <= n; i++) {
scanf("%d%d", &Lamb[i].t, &Lamb[i].x);
}
for (int i = 1; i <= m; i++) {
ans[i] = 0;
pa[i] = i;
}
sort(Lamb + 1, Lamb + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
if (vis[Lamb[i].t])
continue;
vis[Lamb[i].t] = 1;
for (int j = 0; j * Lamb[i].t + 1 <= m; j+=2) {
for (int k = 1 + j * Lamb[i].t; k <= m && k <= (j+1) * Lamb[i].t; k++) {
if (ans[k] == 0) {
ans[k] = Lamb[i].x;
pa[k-1] = k;
}
else
k = find(k);
}
}
}
printf("Case #%d: ", cas++);
for (int i = 1; i <= m; i++) {
printf("%d", ans[i]);
if (i == m)
printf("\n");
else
printf(" ");
}
}
return 0;
}