题目链接:jzoj 6660 / luogu 4087
题目
最初,农夫约翰的每头奶牛每天生产加仑的牛奶。由于随着时间的推移,奶牛的产奶量可能会发生变化,农夫约翰决定定期对奶牛的产奶量进行测量,并将其记录在日志中。
他的日志中的记录如下:
第一个条目表明:在第天,号奶牛的产奶量比上次测量时降低了加仑。
第二个条目表明:在第天,号奶牛的产奶量比上次测量时增加了加仑。
农夫约翰只有在任何一天内做最多一次测量的时间(即每天最多做一次测量,但可能不做)。不幸的是,约翰有点杂乱无章,他不一定按照时间顺序记下测量结果。为了保持奶牛的产奶动力,农夫约翰自豪地在谷仓的墙上展示了目前产奶量最高的奶牛的照片(如果有若干头奶牛的产奶量最高,他就会展示所有的图片)。
请求出约翰需要调整所展示的照片的次数。
请注意,农夫约翰有一大群奶牛。所以尽管日志中记录了一些奶牛改变了产奶量,但仍然还有很多奶牛的产奶量保持在加仑。
输入
第一行是两个整数和,分别表示测量的次数和初始产奶量。
接下来行,每行为一次测量。每行三个数:分别表示日期一(在整数范围内),奶牛的编号(在整数范围内),该奶牛的产奶量变化值(一个非负数)。无论如何,每头奶牛的产奶量永远保证在范围
内。
输出
请输出约翰总共调整所展示的照片的次数。
样例输入
4 10
7 3 +3
4 2 -1
9 3 -1
1 1 +2
样例输出
3
思路
这道题可以用线段树做,但是我用的是模拟。
就是维护第一大和第二大(这样才能省时间),具体怎么搞看代码吧。
(代码中的找新的第二名就是直接暴力找)
代码
#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node {
int day, num, add;
}a[1000001];
int n, G, cnt = 100, cow[1000001], maxn, maxx, sec, sex, ans;
map<int, int>mapp;
bool cmp(node x, node y) {
return x.day < y.day;
}
void findsec() {//暴力找到第二名
sec = -2147483647;
sex = 0;
for (int j = 1; j <= cnt; j++) {
if (cow[j] != maxn && cow[j] > sec) {
sec = cow[j];
sex = 1;
}
else if (cow[j] == sec) sex++;
}
}
int main() {
// freopen("measurement.in", "r", stdin);
// freopen("measurement.out", "w", stdout);
scanf("%d %d", &n, &G);//读入
for (int i = 1; i <= n; i++) {
scanf("%d %d %d", &a[i].day, &a[i].num, &a[i].add);//读入
}
sort(a + 1, a + n + 1, cmp);//按时间排序
for (int i = 1; i <= n; i++) {
if (!mapp[a[i].num]) mapp[a[i].num] = ++cnt;//离散化
if (cow[mapp[a[i].num]] == maxn) {//原来是最大
cow[mapp[a[i].num]] += a[i].add;//数量改变
if (a[i].add > 0) {//产奶量增加
if (maxx != 1) {//原来第一名不止一个
sec = maxn;
sex = maxx - 1;
maxx = 1;
ans++;
}
maxn = cow[mapp[a[i].num]];
}
else {//产奶量减少
if (maxx != 1) {//原来第一名不止一个
maxx--;
ans++;
if (cow[mapp[a[i].num]] > sec) {//还比原来的第一名大
sec = cow[mapp[a[i].num]];
sex = 1;
}
else if (cow[mapp[a[i].num]] == sec) sex++;//跟原来的第二名一样大
}
else {//原来第一名只有一个
if(cow[mapp[a[i].num]] > sec) maxn = cow[mapp[a[i].num]];//还是比第二名高
else if(cow[mapp[a[i].num]] == sec) {//跟第二名一样高(第二名变成了第一名,要重新找第二名)
maxn = sec;
maxx = sex + 1;
findsec();
ans++;
}
else {//比第二名低
maxn = sec;
maxx = sex;
findsec();
ans++;
}
}
}
}
else if (cow[mapp[a[i].num]] == sec) {//原来是第二名
cow[mapp[a[i].num]] += a[i].add;//加h值
if(a[i].add < 0) {//产量减少
sex--;
if(!sex) findsec();//要重新去找第二名
}
else {//产量增加
if (cow[mapp[a[i].num]] == maxn) {//现在跟第一名一样多
sex--;
maxx++;
ans++;
if (!sex) findsec();
}
else if (cow[mapp[a[i].num]] > maxn) {//超过了第一名
sec = cow[mapp[a[i].num]];
sex = 1;
swap(maxn, sec);
swap(maxx, sex);
ans++;
}
else {//没有超过第一名(那肯定是第二名)
sec = cow[mapp[a[i].num]];
sex = 1;
}
}
}
else {//原来不是第一也不是第二
cow[mapp[a[i].num]] += a[i].add;//加值
if (cow[mapp[a[i].num]] == maxn) {//已经是和第一同样大了
maxx++;
ans++;
}
else if (cow[mapp[a[i].num]] == sec) {//已经和第二同样大了
sex++;
}
else if (cow[mapp[a[i].num]] > maxn) {//已经是最大的了
sec = cow[mapp[a[i].num]];
sex = 1;
swap(maxn, sec);
swap(maxx, sex);
ans++;
}
else if (cow[mapp[a[i].num]] > sec){//比第二大,但是比第一小
sec = cow[mapp[a[i].num]];
sex = 1;
}
}
}
printf("%d", ans);//输出
// fclose(stdin);
// fclose(stdout);
return 0;
}