SCP 2024 第二轮(复赛 J 组)模拟 T3 三目运算 题解

SCP 2024 第二轮(复赛 J 组)模拟 T3 三目运算 题解

题目简述

求一个只含三目运算符和数的含 x x x 式子代入若干 x x x 的值。

做法

观察样例。
在这里插入图片描述

我们发现,每次判断都是先看红色部分。如果结果为真判断黄色,为假判断蓝色。接下来同理。
判断过程可以看作一个树形图。
在这里插入图片描述
每个询问从上往下 dfs 即可。
可以获得 72 p t s 72pts 72pts 的高分

在这里插入图片描述

为什么被卡了?
因为如果树是一条链,单次查询为 O ( n ) O(n) O(n),于是 TLE 了。

考虑离线,把所有询问读进来,并排序。
每次到一个结点时,二分判断那部分往左走,哪部分往右走。
这回不会再被卡了。时间复杂度 O ( n log ⁡ ( q ) ) O(n \log(q)) O(nlog(q))

可以获得 100 p t s 100pts 100pts 的高分。
在这里插入图片描述

代码

代码放在下面,建议大家不要 Ctrl c + Ctrl v,自己写一遍会有更大的进步。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 2000010, M = 300010;

int n, m, q;
char s[N];
int h[M], e[M], val[M], ne[M], idx, tot;
int w[M], st[M];
struct Query
{
	int id, x;
	bool operator <(const Query &W)
	{
		return x < W.x;
	}
}query[M];
int res[M];

void add(int a, int b, int c)
{
	e[tot] = b, val[tot] = c, ne[tot] = h[a], h[a] = tot ++ ;
}

int dfs1(int& u)
{
	if (s[u] >= '0' && s[u] <= '9')
	{
		w[ ++ idx] = s[u] - '0', st[idx] = 1;
		for (u ++ ; u <= n && s[u] >= '0' && s[u] <= '9'; u ++ )
			w[idx] = w[idx] * 10 + s[u] - '0';
		return idx;
	}
	else
	{
		u ++ ;
		++ idx;
		int v = idx;
		if (s[u] == '>') st[v] = 2;
		else st[v] = 3;
		u ++ ;
		w[v] = s[u] - '0';
		for (u ++ ; u <= n && s[u] >= '0' && s[u] <= '9'; u ++ )
			w[v] = w[v] * 10 + s[u] - '0';
		u ++ ;
		int left = dfs1(u);
		u ++ ;
		int right = dfs1(u);
		add(v, left, 0), add(v, right, 1);
		return v;
	}
}

void dfs2(int u, int l, int r)
{
	if (st[u] == 1)
	{
		for (int i = l; i <= r; i ++ )
			res[query[i].id] = w[u];
		return;
	}
	
	for (int i = h[u]; ~i; i = ne[i])
	{
		int j = e[i];
		if (st[u] == 2) // '>'
		{
			if (val[i] == 0) // '>'
			{
				int L = l, R = r + 1;
				while (L < R)
				{
					int mid = L + R >> 1;
					if (query[mid].x > w[u]) R = mid;
					else L = mid + 1;
				}
				if (L != r + 1) dfs2(j, L, r);
			}
			else // '<='
			{
				int L = l - 1, R = r;
				while (L < R)
				{
					int mid = L + R + 1 >> 1;
					if (query[mid].x <= w[u]) L = mid;
					else R = mid - 1;
				}
				if (R != l - 1) dfs2(j, l, R);
			}
		}
		if (st[u] == 3) // '<'
		{
			if (val[i] == 0) // '<'
			{
				int L = l - 1, R = r;
				while (L < R)
				{
					int mid = L + R + 1 >> 1;
					if (query[mid].x < w[u]) L = mid;
					else R = mid - 1;
				}
				if (R != l - 1) dfs2(j, l, R);
			}
			else // '>=';
			{
				int L = l, R = r + 1;
				while (L < R)
				{
					int mid = L + R >> 1;
					if (query[mid].x >= w[u]) R = mid;
					else L = mid + 1;
				}
				if (L != r + 1) dfs2(j, L, r);
			}
		}
	}
}

int main()
{
	scanf("%d%d", &m, &q);
	scanf("%s", s + 1);
	n = strlen(s + 1);
	memset(h, -1, sizeof h);
	int first = 1;
	int root = dfs1(first);
	for (int i = 0; i < q; i ++ )
	{
		int x;
		scanf("%d", &x);
		query[i] = {i, x};
	}
	
	sort(query, query + q);
	
	dfs2(root, 0, q - 1);
	
	for (int i = 0; i < q; i ++ ) printf("%d\n", res[i]);
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值