2017 ACM Arabella Collegiate Programming Contest Monkeying Around

解决一道算法题目,关于猴子们听笑话的反应,通过线段树和树状数组来记录每个猴子的状态变化,最终确定教授回来时坐在椅子上的猴子数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Monkeying Around
time limit per test
2.0 s
memory limit per test
256 MB
input
standard input
output
standard output

When the monkey professor leaves his class for a short time, all the monkeys go bananas. N monkeys are lined up sitting side by side on their chairs. They each have the same joke book. Before the professor returns, M jokes were heard.

Each of the M jokes are said in the order given and have the following properties:

xi - position of the monkey who said it.

li – index of the joke in the book.

ki – volume the monkey says that joke.

When the monkey at position xi says the joke li, all monkeys at a distance less than or equal to ki from that monkey (including the monkey who said the joke) will fall off their chairs in laughter if they have never heard the joke li before.

If the joke li has been heard anytime during the past before, and the monkey hears it again, then he will sit back up in his chair.

A monkey can fall off his chair more than once (every time he hears a new joke), and if he is already on the ground and hears a new joke, he will stay on the ground.

Can you figure out how many monkeys will be in their seats by the time the professor comes back?

Input

The first line of input is T – the number of test cases.

The first line of each test case is NM (1 ≤ N ≤ 105) (1 ≤ M ≤ 105) – the number of monkeys in the class, and the number of jokes said before the professor returns.

The next M lines contain the description of each joke: xi, li, ki (1 ≤ xi ≤ N) (1 ≤ li ≤ 105) (0 ≤ ki ≤ N).

Output

For each test case, output on a line a single integer - the number of monkeys in their seats after all jokes have been said.

Example
input
1
10 7
3 11 0
3 11 2
5 12 1
8 13 2
7 11 2
10 12 1
9 12 0
output
3

题意:有n只猴子做成一排,标号为1~n,他们一共讲了m次笑话,每次第x只猴子讲了编号为l的笑话,并且距离他k的猴子听到这个笑话,对听到笑话的猴子来说,如果他们之前没有听到过这个笑话,他们就会笑得掉到地上,否则他们会坐在凳子上。问讲了m个笑话后,有多少猴子在座位上

解题思路:因为猴子的状态是强制改变的,所以对每只猴子来说,他们的状态只受最后一个笑话听过几次影响。然后就是线段树处理出每只猴子最后听的是编号为几的笑话,树状数组维护每只猴子这个笑话听过几次


#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#include <algorithm>  
#include <cmath>  
#include <map>  
#include <set>  
#include <stack>  
#include <queue>  
#include <vector>  
#include <bitset>  
#include <functional>  

using namespace std;

#define LL long long  
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;

int n, m, x, y, z;
int a[maxn << 2], lazy[maxn << 2];
int sum[maxn];
vector<pair<int, int> > g1[maxn];
vector<int>g2[maxn];

void build(int k, int l, int r)
{
	a[k] = lazy[k] = 0;
	if (l == r) return;
	int mid = (l + r) / 2;
	build(k << 1, l, mid);
	build(k << 1 | 1, mid + 1, r);
}

void pushDown(int k)
{
	a[k << 1] = a[k << 1 | 1] = lazy[k];
	lazy[k << 1] = lazy[k << 1 | 1] = lazy[k];
	lazy[k] = 0;
}

void update(int k, int l, int r, int ll, int rr, int val)
{
	if (ll <= l && r <= rr)
	{
		a[k] = lazy[k] = val;
		return;
	}
	int mid = (l + r) / 2;
	if (lazy[k]) pushDown(k);
	if (ll <= mid) update(k << 1, l, mid, ll, rr, val);
	if (rr > mid)  update(k << 1 | 1, mid + 1, r, ll, rr, val);
}

int get(int k, int l, int r, int p)
{
	if (l == r) return a[k];
	int mid = (l + r) / 2;
	if (lazy[k]) pushDown(k);
	if (p <= mid) return get(k << 1, l, mid, p);
	return get(k << 1 | 1, mid + 1, r, p);
}

int lowbit(int k)
{
	return k & -k;
}

void update(int k, int val)
{
	for (int i = k; i < maxn; i += lowbit(i))
		sum[i] += val;
}

int getsum(int k)
{
	int ans = 0;
	for (int i = k; i; i -= lowbit(i))
		ans = ans + sum[i];
	return ans;
}

int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &m);
		for (int i = 0; i < maxn; i++)
		{
			g1[i].clear();
			g2[i].clear();
		}
		build(1, 1, n);
		for (int i = 1; i <= m; i++)
		{
			scanf("%d%d%d", &x, &y, &z);
			int L = max(1, x - z);
			int R = min(n, x + z);
			update(1, 1, n, L, R, y);
			g1[y].push_back(make_pair(L, R));
		}
		for (int i = 1; i <= n; i++)
		{
			int k = get(1, 1, n, i);
			g2[k].push_back(i);
		}
		int ans = g2[0].size();
		for (int i = 1; i < maxn; i++)
		{
			int Size1 = g1[i].size(), Size2 = g2[i].size();
			if (Size1 == 0 || Size2 == 0) continue;
			for (int j = 0; j < Size1; j++)
			{
				pair<int, int>p = g1[i][j];
				update(p.first, 1);
				update(p.second + 1, -1);
			}
			for (int j = 0; j < Size2; j++)
			{
				int p = g2[i][j];
				if (getsum(p) >= 2) ans++;
			}
			for (int j = 0; j < Size1; j++)
			{
				pair<int, int>p = g1[i][j];
				update(p.first, -1);
				update(p.second + 1, 1);
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值