[题解][Codeforces 1139A~1139F]Codeforces Round #548 (Div. 2) 简要题解

博客详细解析了Codeforces Round #548 (Div. 2)比赛中的A到F六道题目,包括题意、题解和代码实现。涉及算法包括:子串偶数判断、数组优化、树形DP、莫比乌斯反演 + 期望DP、二分图匹配和扫描线 + 树状数组。

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

  • 终于 rank < 10 了

题目

洛谷 RemoteJudge

Codeforces

A

题意

  • 一个长度为 n n n 的数字串 s s s
  • s s s 有多少个子串,满足子串内的数字顺次连接后得到的数是偶数
  • 1 ≤ n ≤ 65000 1\le n\le 65000 1n65000 s s s 不包含 0 0 0

题解

  • ∑ i = 1 n i [ s [ i ] 是 偶 数 ] \sum_{i=1}^ni[s[i]是偶数] i=1ni[s[i]]

代码

#include <bits/stdc++.h>

// 20030830

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

typedef long long ll;

const int N = 1e5 + 5;

int n;
char s[N];
ll ans;

int main()
{
	n = read();
	scanf("%s", s + 1);
	for (int i = 1; i <= n; i++)
		if (s[i] - '0' + 1 & 1) ans += i;
	std::cout << ans << std::endl;
	return 0;
}

B

题意

  • 一个长度为 n n n 的正整数数组 a a a
  • 求一个长度为 n n n 的非负数组 x x x ,满足
  • (1)对于所有的 1 ≤ i ≤ n 1\le i\le n 1in ,有 0 ≤ x i ≤ a i 0\le x_i\le a_i 0xiai
  • (2)对于所有的 1 ≤ j &lt; i ≤ n 1\le j&lt;i\le n 1j<in ,有 x j = 0 x_j=0 xj=0 x j &lt; x i x_j&lt;x_i xj<xi
  • (3)最大化 ∑ i = 1 n x i \sum_{i=1}^nx_i i=1nxi
  • 求这个最大值
  • 1 ≤ n ≤ 2 × 1 0 5 1\le n\le 2\times10^5 1n2×105 1 ≤ a i ≤ 1 0 9 1\le a_i\le 10^9 1ai109

题解

  • 从右到左考虑,显然每个 x i x_i xi 需要取到它能取到的最大值
  • 也就是说
  • (1) x n = a n x_n=a_n xn=an
  • (2) x i = min ⁡ ( a i , max ⁡ ( 0 , x i + 1 − 1 ) ) x_i=\min(a_i,\max(0,x_{i+1}-1)) xi=min(ai,max(0,xi+11)) 1 ≤ i &lt; n 1\le i&lt;n 1i<n

代码

#include <bits/stdc++.h>

// 20030830

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

template <class T>
inline T Min(const T &a, const T &b) {return a < b ? a : b;}

typedef long long ll;

const int N = 2e5 + 5;

int n, a[N], wt;
ll ans;

int main()
{
	n = read();
	for (int i = 1; i <= n; i++) a[i] = read(); wt = a[n] + 1;
	for (int i = n; i >= 1; i--)
	{
		wt--; if (wt < 0) wt = 0;
		wt = Min(wt, a[i]);
		ans += wt;
	}
	std::cout << ans << std::endl;
	return 0;
}

C

题意

  • 一棵 n n n 个节点的树,边有红边和黑边
  • 求有多少个节点序列 a 1 … k a_{1\dots k} a1k
  • 满足 a 1 a_1 a1 a 2 a_2 a2 a 2 a_2 a2 a 3 a_3 a3 … \dots a k − 1 a_{k-1} ak1 a k a_k ak k − 1 k-1 k1 条路径中存在一条经过了至少一条黑边
  • 2 ≤ n ≤ 1 0 5 2\le n\le10^5 2n105 2 ≤ k ≤ 100 2\le k\le100 2k100

题解

  • 容易想到一个经典的 O(nk) 树形 DP
  • 用总方案数 n k n^k nk 减掉不经过黑边的方案数
  • 显然,如果只加入所有红边,那么不经过黑边的方案数,就是节点序列 a 1 … k a_{1\dots k} a1k 中所有点位于同一个连通块内的方案数
  • 用并查集维护连通块大小
  • 答案就是 n k n^k nk 减去所有连通块的大小的 k k k 次幂之和

代码

#include <bits/stdc++.h>

// 20030830

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

const int N = 1e5 + 5, ZZQ = 1e9 + 7;

int qpow(int a, int b)
{
	int res = 1;
	while (b)
	{
		if (b & 1) res = 1ll * res * a % ZZQ;
		a = 1ll * a * a % ZZQ;
		b >>= 1;
	}
	return res;
}

int n, k, fa[N], sze[N], ans;

int cx(int x)
{
	if (fa[x] != x) fa[x] = cx(fa[x]);
	return fa[x];
}

void zm(int x, int y)
{
	int ix = cx(x), iy = cx(y);
	if (ix != iy) fa[iy] = ix, sze[ix] += sze[iy];
}

int main()
{
	int x, y, z;
	n = read(); k = read();
	for (int i = 1; i <= n; i++) fa[i] = i, sze[i] = 1;
	for (int i = 1; i < n; i++)
	{
		x = read(); y = read(); z = read();
		if (!z) zm(x, y);
	}
	for (int i = 1; i <= n; i++)
		if (fa[i] == i) ans = (qpow(sze[i], k) + ans) % ZZQ;
	std::cout << (qpow(n, k) - ans + ZZQ) % ZZQ << std::endl;
	return 0;
}

D

题意

  • 给定正整数 m m m ,你有一个空集合 a a a
  • 每次你可以等概率随机一个 [ 1 , m ] [1,m] [1,m] 内的正整数加入集合 a a a
  • 加入之后,如果集合 a a a 内所有数的 gcd ⁡ \gcd gcd 1 1 1 则结束过程,否则继续随机
  • 求过程结束后集合 a a a 的期望大小
  • 1 ≤ m ≤ 100000 1\le m\le 100000 1m100000

算法:莫比乌斯反演 + 期望 DP

  • 状态 f [ i ] f[i] f[i] 表示当前集合 a a a gcd ⁡ \gcd gcd i i i 的情况下,期望加入多少个数之后这个 gcd ⁡ \gcd gcd 变成 1 1 1
  • 显然有
  • f [ 1 ] = 0 f[1]=0 f[1]=0
  • f [ i ] = 1 + 1 m ∑ j = 1 m f [ gcd ⁡ ( i , j ) ] f[i]=1+\frac 1m\sum_{j=1}^mf[\gcd(i,j)] f[i]=1+m1j=1mf[gcd(i,j)]
  • 发现 gcd ⁡ ( i , j ) \gcd(i,j) gcd(i,j) 的取值个数只有 i i i 的约数个数,所以把枚举 j j j 改成枚举 gcd ⁡ ( i , j ) \gcd(i,j) gcd(i,j)
  • f [ i ] + 1 + 1 m ∑ d ∣ i f [ d ] × c n t ( d , i ) f[i]+1+\frac 1m\sum_{d|i}f[d]\times cnt(d,i) f[i]+1+m1dif[d]×cnt(d,i)
  • c n t ( d , i ) cnt(d,i) cnt(d,i) 表示 [ 1 , m ] [1,m] [1,m] 内有多少个数与 i i i gcd ⁡ \gcd gcd 等于 d d d
  • 另设 g ( i , j ) g(i,j) g(i,j) 表示 [ 1 , i ] [1,i] [1,i] 内有多少个数与 j j j 互质
  • 显然有 c n t ( d , i ) = g ( ⌊ m d ⌋ , i d ) cnt(d,i)=g(\lfloor\frac md\rfloor,\frac id) cnt(d,i)=g(dm,di)
  • 注意到 ∑ i = 1 m m i = O ( m log ⁡ m ) \sum_{i=1}^m\frac mi=O(m\log m) i=1mim=O(mlogm)
  • 所以考虑求出所有的 i j ≤ m ij\le m ijm ,对应 g ( ⌊ m i ⌋ , j ) g(\lfloor\frac mi\rfloor,j) g(im,j) 的值
  • 那么对于给定的 a ≥ b a\ge b ab ,如何求有多少个 1 ≤ i ≤ a 1\le i\le a 1ia 满足 gcd ⁡ ( i , b ) = 1 \gcd(i,b)=1 gcd(i,b)=1 呢?
  • 如果不是满足 gcd ⁡ ( i , b ) = 1 \gcd(i,b)=1 gcd(i,b)=1 而是满足 x ∣ gcd ⁡ ( i , b ) x|\gcd(i,b) xgcd(i,b) ,则这显然为 ⌊ a x ⌋ \lfloor\frac ax\rfloor xa
  • 所以,考虑反演,得
  • g ( a , b ) = ∑ x ∣ b μ ( x ) ⌊ a x ⌋ g(a,b)=\sum_{x|b}\mu(x)\lfloor\frac ax\rfloor g(a,b)=xbμ(x)xa
  • 线性筛 μ \mu μ 之后就可以在 O ( b 的 约 数 个 数 ) O(b的约数个数) O(b) 的时间内求出
  • D ( x ) D(x) D(x) x x x 的约数个数,那么对每对 i j ≤ m ij\le m ijm 进行计算的总复杂度为
  • ∑ i = 1 m ∑ j = 1 ⌊ m i ⌋ D ( j ) = ∑ i = 1 m ∑ j = 1 ⌊ m i ⌋ ⌊ ⌊ m i ⌋ j ⌋ = ∑ i = 1 m ⌊ m i ⌋ log ⁡ m = O ( m log ⁡ 2 m ) \sum_{i=1}^m\sum_{j=1}^{\lfloor\frac mi\rfloor}D(j)=\sum_{i=1}^m\sum_{j=1}^{\lfloor\frac mi\rfloor}\lfloor\frac{\lfloor\frac mi\rfloor}j\rfloor=\sum_{i=1}^m\lfloor\frac mi\rfloor\log m=O(m\log^2m) i=1mj=1imD(j)=i=1mj=1imjim=i=1mimlogm=O(mlog2m)
  • 回到这个转移
  • f [ i ] + 1 + 1 m ∑ d ∣ i f [ d ] × c n t ( d , i ) f[i]+1+\frac 1m\sum_{d|i}f[d]\times cnt(d,i) f[i]+1+m1dif[d]×cnt(d,i)
  • 发现 d d d 可以等于 i i i ,得不到转移的目的,所以做一些移项
  • ( 1 − c n t ( i , i ) m ) f [ i ] = 1 + 1 m ∑ d ∣ i , d ≠ i f [ d ] × c n t ( d , i ) (1-\frac{cnt(i,i)}m)f[i]=1+\frac1m\sum_{d|i,d\ne i}f[d]\times cnt(d,i) (1mcnt(i,i))f[i]=1+m1di,d̸=if[d]×cnt(d,i)
  • f [ i ] = 1 1 − c n t ( i , i ) m ( 1 + 1 m ∑ d ∣ i , d ≠ i f [ d ] × c n t ( d , i ) ) f[i]=\frac1{1-\frac{cnt(i,i)}m}(1+\frac1m\sum_{d|i,d\ne i}f[d]\times cnt(d,i)) f[i]=1mcnt(i,i)1(1+m1di,d̸=if[d]×cnt(d,i))
  • 于是我们就可以转移了
  • 考虑如何算答案
  • 由于第一个数可以随便取,所以答案为
  • 1 m ∑ i = 1 m ( 1 + f [ i ] ) \frac1m\sum_{i=1}^m(1+f[i]) m1i=1m(1+f[i])
  • 看到某人的提交记录里有吊打标算的非 DP 做法,复杂度仿佛是 O ( m log ⁡ m ) O(m\log m) O(mlogm) ,所以有更优做法欢迎提出

代码

  • 该代码中的 f [ i ] f[i] f[i] 表示的是题解中的 f [ i ] f[i] f[i] 加一,答案为 1 m ∑ i = 1 m f [ i ] \frac1m\sum_{i=1}^mf[i] m1i=1mf[i] ,边界为 f [ 1 ] = 1 f[1]=1 f[1]=1 ,见谅
#include <bits/stdc++.h>

// 20030830

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

const int N = 1e5 + 5, ZZQ = 1e9 + 7;

int qpow(int a, int b)
{
	int res = 1;
	while (b)
	{
		if (b & 1) res = 1ll * res * a % ZZQ;
		a = 1ll * a * a % ZZQ;
		b >>= 1;
	}
	return res;
}

int n, f[N], miu[N], tot, pri[N], inv[N], wt[N], num[N], res[N], ans;
bool mark[N];
std::vector<int> divi[N], cont[N];

int solve(int n, int m)
{
	int tt = divi[m].size(), res = 0;
	for (int i = 0; i < tt; i++)
	{
		int x = divi[m][i];
		res += miu[x] * (n / x);
	}
	return res;
}

void sieve()
{
	mark[0] = mark[miu[1] = 1] = 1;
	for (int i = 2; i <= n; i++)
	{
		if (!mark[i]) miu[pri[++tot] = i] = -1;
		for (int j = 1; j <= tot; j++)
		{
			if (1ll * i * pri[j] > n) break;
			mark[i * pri[j]] = 1;
			if (i % pri[j] == 0) break;
			else miu[i * pri[j]] = -miu[i];
		}
	}
	for (int i = 1; i <= n; i++)
		for (int j = i; j <= n; j += i)
			divi[j].push_back(i);
	for (int i = 1; i <= n;)
	{
		int nxt = n / (n / i);
		for (int j = 1; j <= n / i; j++) res[j] = solve(n / i, j);
		for (int j = i; j <= nxt; j++)
			for (int k = j; k <= n; k += j)
				cont[k].push_back(res[k / j]);
		i = nxt + 1;
	}
}

int main()
{
	n = read();
	inv[1] = 1;
	for (int i = 2; i <= n; i++)
		inv[i] = 1ll * (ZZQ - ZZQ / i) * inv[ZZQ % i] % ZZQ;
	sieve();
	f[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		int tt = divi[i].size();
		for (int j = 0; j < tt; j++)
			wt[j + 1] = 1ll * inv[n] * cont[i][j] % ZZQ, num[j + 1] = divi[i][j];
		int qt = qpow((1 - wt[tt] + ZZQ) % ZZQ, ZZQ - 2);
		for (int j = 1; j < tt; j++) wt[j] = 1ll * wt[j] * qt % ZZQ;
		f[i] = qt;
		for (int j = 1; j < tt; j++)
			f[i] = (1ll * wt[j] * f[num[j]] + f[i]) % ZZQ;
	}
	for (int i = 1; i <= n; i++)
		ans = (1ll * inv[n] * f[i] + ans) % ZZQ;
	std::cout << ans << std::endl;
	return 0;
}

E

题意

  • m m m 个集合和 n n n 个元素,每个元素一开始属于恰好一个集合,且第 i i i 个元素的属性值为 p i p_i pi
  • 在每个集合中挑选一个元素(如果该集合为空就不要挑选),使得挑选出的所有元素的属性值的 mex \text{mex} mex 最大
  • mex \text{mex} mex 表示最小没有出现过的自然数
  • 你需要在每次删掉一个元素之后回答这个 mex \text{mex} mex 的最大值
  • 1 ≤ m ≤ n ≤ 5000 1\le m\le n\le5000 1mn5000 0 ≤ p i ≤ 5000 0\le p_i\le5000 0pi5000

算法:二分图匹配

  • 建一张二分图,一侧是属性值,一侧是集合,对于每个元素 i i i p i p_i pi 向其所属集合连一条边
  • 这样,如果 x x x 为满足属性值 [ 0 , x ] [0,x] [0,x] 都能找到匹配的最大 x x x ,答案就是 x + 1 x+1 x+1
  • 发现二分图删边不好处理,所以考虑倒着加边,在加边的过程中维护最大匹配
  • 维护当前的最大 x x x
  • 当加一条边之后,需要更新匹配数
  • 具体地,尝试对点 x + 1 x+1 x+1 寻找匹配
  • 如果找得到匹配则将 x x x 加一,否则停止当前的匹配
  • 由于属性值一侧的每个点最多寻找一次匹配,所以复杂度 O ( n max ⁡ p ) O(n\max p) O(nmaxp)

代码

#include <bits/stdc++.h>

// 20030830

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

template <class T>
inline T Max(const T &a, const T &b) {return a > b ? a : b;}

const int N = 3e4 + 5;

int n, m, tot, p[N], c[N], d, k[N], ecnt, nxt[N], adj[N], go[N], ans[N],
QAQ, vis[N], my[N], now;
bool del[N];

void add_edge(int u, int v)
{
	nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
}

bool dfs(int u)
{
	for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
		if (vis[v] < QAQ)
		{
			vis[v] = QAQ;
			if (my[v] == -1 || dfs(my[v]))
				return my[v] = u, 1;
		}
	return 0;
}

bool find_match(int x)
{
	QAQ++; return dfs(x);
}

int main()
{
	memset(my, -1, sizeof(my));
	n = read(); m = read();
	for (int i = 1; i <= n; i++) tot = Max(tot, p[i] = read());
	for (int i = 1; i <= n; i++) c[i] = read();
	d = read();
	for (int i = 1; i <= d; i++) del[k[i] = read()] = 1;
	for (int i = 1; i <= n; i++) if (!del[i]) add_edge(p[i], tot + c[i]);
	for (int i = d; i >= 1; i--)
	{
		while (now <= tot && find_match(now)) now++;
		ans[i] = now;
		add_edge(p[k[i]], tot + c[k[i]]);
	}
	for (int i = 1; i <= d; i++) printf("%d\n", ans[i]);
	return 0;
}

F

题意

  • n n n 种菜和 m m m 个人
  • 每种菜 i i i 有三个属性 p i , s i , b i p_i,s_i,b_i pi,si,bi
  • 每个人 j j j 有两个属性 i n c j , p r e f j inc_j,pref_j incj,prefj
  • 一个人 j j j 能品尝菜 i i i 当且仅当 p i ≤ i n c j ≤ s i p_i\le inc_j\le s_i piincjsi ∣ b i − p r e f j ∣ ≤ i n c j − p i |b_i-pref_j|\le inc_j-p_i biprefjincjpi
  • 求每个人能品尝多少种菜
  • 1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1n,m105 ,其他数据均为 1 0 9 10^9 109 级别

算法:扫描线 + 树状数组

  • 此题有一个非常套路的 O ( ( n + m ) log ⁡ 2 n ) O((n+m)\log^2n) O((n+m)log2n) 做法( CDQ 分治)和一个比较妙的官方题解做法,复杂度少一个 log ⁡ \log log ,下面只讨论后者
  • 首先, ∣ b i − p r e f j ∣ ≤ i n c j − p i |b_i-pref_j|\le inc_j-p_i biprefjincjpi 就相当于 b i − p r e f j ≤ i n c j − p i b_i-pref_j\le inc_j-p_i biprefjincjpi p r e f j − b i ≤ i n c j − p i pref_j-b_i\le inc_j-p_i prefjbiincjpi
  • 把问题抽象到二维平面上,一个点 ( x , y ) (x,y) (x,y) 表示一个人的 i n c inc inc x x x p r e f pref pref y y y
  • 整理一下得出条件
  • (1) p i ≤ i n c j ≤ s i p_i\le inc_j\le s_i piincjsi
  • (2) i n c j + p r e f j ≥ b i + p i inc_j+pref_j\ge b_i+p_i incj+prefjbi+pi
  • (3) p r e f j − i n c j ≤ b i − p i pref_j-inc_j\le b_i-p_i prefjincjbipi
  • 这相当于点 ( i n c j , p r e f j ) (inc_j,pref_j) (incj,prefj) 位于如下图所示的三角形内(含边界)
    在这里插入图片描述
  • 考虑扫描线,把所有人离线按照 i n c inc inc 排序,按照 x x x 坐标递增的顺序扫描,当扫到 b i b_i bi 时加入第 i i i 个三角形的影响,扫到 s i + 1 s_i+1 si+1 时去除第 i i i 个三角形的影响
  • 我们对于每个人 ( i n c j , p r e f j ) (inc_j,pref_j) (incj,prefj) 需要询问这个点在多少个三角形内
  • 考虑差分,也就是说当 x = x 0 x=x_0 x=x0 时,如果直线 x = x 0 x=x_0 x=x0 经过了第 i i i 个三角形且 y y y 坐标范围 [ l , r ] [l,r] [l,r] 被第 i i i 个三角形覆盖,则在 l l l 处贡献 1 1 1 r + 1 r+1 r+1 处贡献 − 1 -1 1 ,则当 i n c j = x 0 inc_j=x_0 incj=x0 时,单点询问 ( i n c j , p r e f j ) (inc_j,pref_j) (incj,prefj) 转化成询问前缀和 p r e f j pref_j prefj
  • 于是我们考虑第 i i i 个三角形的影响,可以看成
  • (1)在直线 x + y = b i + p i x+y=b_i+p_i x+y=bi+pi 上贡献 1 1 1
  • (2)在直线 y − x = b i − p i + 1 y-x=b_i-p_i+1 yx=bipi+1 上贡献 − 1 -1 1
  • 消除第 i i i 个三角形的影响则同理
  • 询问相当于询问横坐标为 i n c j inc_j incj ,纵坐标不超过 p r e f j pref_j prefj 的贡献之和
  • 用两个数据结构 A A A B B B 分别记录 x + y x+y x+y y − x y-x yx 的贡献
  • 直线 x + y = k x+y=k x+y=k 能为 ( i n c j , p r e f j ) (inc_j,pref_j) (incj,prefj) 贡献当且仅当 k ≤ i n c j + p r e f j k\le inc_j+pref_j kincj+prefj
  • 所以加入第 i i i 个三角形时,在数据结构 A A A b i + p i b_i+p_i bi+pi 处进行单点加 1 1 1
  • 直线 y − x = k y-x=k yx=k 能为询问贡献当且仅当 k ≤ p r e f j − i n c j k\le pref_j-inc_j kprefjincj
  • 所以加入第 i i i 个三角形时,在数据结构 B B B b i − p i + 1 b_i-p_i+1 bipi+1 处进行单点加 1 1 1
  • 这样第 j j j 个询问的答案就是当 x x x 扫描到 i n c j inc_j incj 时,数据结构 A A A 的前缀和 i n c j + p r e f j inc_j+pref_j incj+prefj 减去数据结构 B B B 的前缀和 p r e f j − i n c j pref_j-inc_j prefjincj
  • 可以用树状数组等实现
  • 复杂度 O ( ( n + m ) log ⁡ ( n + m ) ) O((n+m)\log(n+m)) O((n+m)log(n+m))

代码

#include <bits/stdc++.h>

// 20030830

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

const int N = 1e5 + 5, M = N << 2;

int n, m, p[N], s[N], b[N], inc[N], pref[N], tot, a[M], A[M], B[M], cnt, ans[N];

struct node
{
	int tm, x, y, op, id;
} que[M];

inline bool comp(node a, node b)
{
	return a.tm < b.tm || (a.tm == b.tm && a.op < b.op);
}

void changeA(int x, int v)
{
	for (; x <= tot; x += x & -x)
		A[x] += v;
}

int askA(int x)
{
	int res = 0;
	for (; x; x -= x & -x)
		res += A[x];
	return res;
}

void changeB(int x, int v)
{
	for (; x <= tot; x += x & -x)
		B[x] += v;
}

int askB(int x)
{
	int res = 0;
	for (; x; x -= x & -x)
		res += B[x];
	return res;
}

int main()
{
	n = read(); m = read();
	for (int i = 1; i <= n; i++) p[i] = read();
	for (int i = 1; i <= n; i++) s[i] = read();
	for (int i = 1; i <= n; i++) b[i] = read();
	for (int i = 1; i <= m; i++) inc[i] = read();
	for (int i = 1; i <= m; i++) pref[i] = read();
	for (int i = 1; i <= n; i++)
		a[++tot] = p[i] + b[i], a[++tot] = b[i] - p[i] + 1;
	for (int i = 1; i <= m; i++)
		a[++tot] = inc[i] + pref[i], a[++tot] = pref[i] - inc[i];
	std::sort(a + 1, a + tot + 1);
	int tt = std::unique(a + 1, a + tot + 1) - a - 1;
	tot = tt;
	for (int i = 1; i <= n; i++)
		que[++cnt] = (node) {p[i], p[i], b[i], 1, 0},
		que[++cnt] = (node) {s[i] + 1, p[i], b[i], -1, 0};
	for (int i = 1; i <= m; i++)
		que[++cnt] = (node) {inc[i], inc[i], pref[i], 2, i};
	std::sort(que + 1, que + cnt + 1, comp);
	for (int i = 1; i <= cnt; i++)
		if (que[i].op <= 1)
		{
			changeA(std::lower_bound(a + 1, a + tot + 1,
				que[i].x + que[i].y) - a, que[i].op);
			changeB(std::lower_bound(a + 1, a + tot + 1,
				que[i].y - que[i].x + 1) - a, que[i].op);
		}
		else ans[que[i].id] = askA(std::lower_bound(a + 1, a + tot + 1,
			que[i].x + que[i].y) - a) -
			askB(std::lower_bound(a + 1, a + tot + 1,
			que[i].y - que[i].x) - a);
	for (int i = 1; i <= m; i++) printf("%d ", ans[i]);
	return puts(""), 0;
}
抱歉,根据提供的引用内容,我无法理解你具体想要问什么问题。请提供更清晰明确的问题,我将竭诚为你解答。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [【CodeforcesCodeforces Round 865 (Div. 2) (补赛)](https://blog.csdn.net/t_mod/article/details/130104033)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值