首页 > 其他分享 >CodeForces 542B Duck Hunt

CodeForces 542B Duck Hunt

时间:2023-09-11 20:23:07浏览次数:49  
标签:rt typedef int max Hunt CodeForces lst Duck ql

洛谷传送门

CF 传送门

首先转化一下,让鸭子不动,猎人往右移动,就相当于开的相邻两枪距离 \(> m\)。

设 \(f_{x, i}\) 为仅考虑 \(r \le x\) 的鸭子,上一次在 \(i\) 开枪,能打到的最大鸭子个数。

\(f_{x - 1} \to f_x\) 时,首先有 \(f_{x, i} = f_{x - 1, i}\)。我们先找到所有 \(r = x\) 的鸭子,设其左端点为 \(l\),将 \(f_{x, l \sim x}\) 区间加 \(1\)。如果在 \(x\) 开枪,有 \(f_{x, x} = \max\limits_{i = 0}^{x - m} f_{x - 1, i}\)。

于是我们需要支持,区间加 \(1\),给单点赋一段前缀 \(\max\)。

但是 \(x\) 高达 \(10^9\),显然我们要优化赋前缀 \(\max\) 的过程。

发现若 \(\max\limits_{i = 0}^{x - m - 1} f_{x, i} < \max\limits_{i = 0}^{x - m} f_{x, i}\),那么 \(f_{x, x - m} > \max\limits_{i = 0}^{x - m - 1} f_{x, i}\)。因为我们区间加 \(1\) 只有 \(O(n)\) 次,所以这样的情况也只会出现 \(O(n)\) 次。考虑出现这种情况的条件:

  • 存在一个鸭子,使得它的 \(l = x - m\);
  • \(f_{x, x - 2m} > \max\limits_{i = 0}^{x - 2m - 1} f_{x, i}\)。

考虑维护一个堆,同时对 \(x\) 扫描线。对于一个鸭子 \([l, x]\),把 \(l + m\) 扔进堆里,表示在这个位置可能出现上面的情况。对于出现上面情况的 \(x\),再把 \(x + m\) 扔进堆里。

code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 12000000;

int n, m, N, ls[maxn], rs[maxn], mx[maxn], tag[maxn], rt, ntot;

struct node {
	int l, r;
	node(int a = 0, int b = 0) : l(a), r(b) {}
};

inline bool operator < (const node &a, const node &b) {
	return a.r > b.r || (a.r == b.r && a.l > b.l);
}

inline void pushup(int x) {
	mx[x] = max(mx[ls[x]], mx[rs[x]]) + tag[x];
}

void update(int &rt, int l, int r, int ql, int qr, int x) {
	if (!rt) {
		rt = ++ntot;
	}
	if (ql <= l && r <= qr) {
		mx[rt] += x;
		tag[rt] += x;
		return;
	}
	int mid = (l + r) >> 1;
	if (ql <= mid) {
		update(ls[rt], l, mid, ql, qr, x);
	}
	if (qr > mid) {
		update(rs[rt], mid + 1, r, ql, qr, x);
	}
	pushup(rt);
}

void modify(int &rt, int l, int r, int x, int y) {
	if (!rt) {
		rt = ++ntot;
	}
	if (l == r) {
		mx[rt] = y;
		return;
	}
	int mid = (l + r) >> 1;
	(x <= mid) ? modify(ls[rt], l, mid, x, y) : modify(rs[rt], mid + 1, r, x, y);
	pushup(rt);
}

int query(int rt, int l, int r, int ql, int qr) {
	if (!rt || ql > qr) {
		return 0;
	}
	if (ql <= l && r <= qr) {
		return mx[rt];
	}
	int mid = (l + r) >> 1, res = 0;
	if (ql <= mid) {
		res = max(res, query(ls[rt], l, mid, ql, qr));
	}
	if (qr > mid) {
		res = max(res, query(rs[rt], mid + 1, r, ql, qr));
	}
	res += tag[rt];
	return res;
}

void solve() {
	scanf("%d%d", &n, &m);
	priority_queue<node> pq;
	for (int i = 1, l, r; i <= n; ++i) {
		scanf("%d%d", &l, &r);
		if (r < 0) {
			continue;
		}
		l = max(0, l);
		pq.emplace(l, r);
		pq.emplace(-1, l);
		N = max(N, r);
	}
	int lst = -1;
	while (pq.size()) {
		int l = pq.top().l, r = pq.top().r;
		pq.pop();
		if (l >= 0) {
			update(rt, 0, N, l, r, 1);
			continue;
		}
		if (r == lst) {
			continue;
		}
		int x = lst >= 0 ? query(rt, 0, N, lst, lst) : 0, y = query(rt, 0, N, 0, r - m);
		if (l == -1 || y > x) {
			lst = r;
			modify(rt, 0, N, r, y);
			if (r + m <= N) {
				pq.emplace(-2, r + m);
			}
		}
	}
	printf("%d\n", mx[rt]);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:rt,typedef,int,max,Hunt,CodeForces,lst,Duck,ql
From: https://www.cnblogs.com/zltzlt-blog/p/17694392.html

相关文章

  • Codeforces Round 896 (Div. 1)
    Preface不管怎么说,最后还是被我苟上橙名了(虽然刚好2100整,不多不少)感觉我在1900~2100之间卡了好久好久,反观我的队友都是打上紫名后随便两三场就打上橙了,狠狠地羞辱我这个铁混子由于暑假集训打的校内排名比较高,作为新队伍也拿到了今年的一场CCPC+一场ICPC的名额,虽然要自费出行但......
  • Codeforces Round 101 (Div. 2) C - E
    C.Queue(思维、排序、构造、*1800)题意:$n$个人排队,为他们构造一组身高,使得$x$的前面有$a_i$个人比他高。如果无法构造满足所有条件的身高序列,输出-1。思路:首先考虑,对于$a_i$较大的人,肯定尽可能地将其往队伍后面放,然后从后往前构造,因为只有$......
  • 【题解】Educational Codeforces Round 142(CF1792)
    没有手速,再加上被E卡了,废掉了。A.GamingForces题目描述:Monocarp正在玩电脑游戏。他打算杀死\(n\)个怪兽,第\(i\)个的血量为\(h_i\)。Monocarp的角色有两个魔法咒语如下,都可以以任意顺序用任意次(可以不用),每次使用相当于一次操作。选择两个怪兽并各扣一滴血。选择......
  • Codeforces Global Round 21 B. NIT Destroys the Universe
    给一个长为\(n\)的数组,可以执行以下操作任意次:选择\(l,r(1\leql<r\leqn)\),让\(\foralli(l\leqi\leqr),a_i=mex(\{a_l,a_{l+1},\cdots,a_{r}\})\)。问最小操作数使得\(\foralli,a_i=0\)。观察:答案\(\leq2\),因为对\([1,n]\)操作不超过两次......
  • Codeforces Round 804 (Div. 2) B. Almost Ternary Matrix
    给两个偶数\(n\)和\(m\)。任务是构造任意一个二进制矩阵,\(n\timesm\)。对于任意\((i,j)\),有且仅有两个邻居的颜色与\(a_{i,j}\)不同。邻居的定义为\(|x-x'|+|y-y'|=1\)。观察:任何\(n\timesm\)的矩阵若作为一个大型矩阵的子矩阵不会受到限制。于是构造......
  • Codeforces Round 807 (Div. 2) B. Mark the Dust Sweeper
    需要打扫\(n\)个房间,第\(i\)个房间有\(a_i\)的积灰。只能使用如下魔法打扫:选择\(i,j,(1\leqi<j\leqn,\min_{k=i}^{j}a_i>0)\)。执行\(a_i=a_i-1,a_j=a_j+1\)。需要将\(1\simn-1\)号房间的积灰全部清空,最少使用多少次魔法。观察一:显......
  • Codeforces Round 811 (Div. 3) A. Everyone Loves to Sleep
    闹钟设有\(n\)个时间点,第\(i\)个时间为\((H_i,M_i)\)。在\(h,m\)时刻入睡,响铃必须起床,问能睡多久。使用\(set<pair<int,int>>\)存储闹铃时刻,然后在其中\(lower_{bound}\)到\(<first\geqh,second\geqm>\)的迭代器\(it\)。若\(it=end\),则\(it=begin......
  • Codeforces Round 819 (Div. 1 + Div. 2) and Grimoire of Code Annual Contest 2022
    给一个长为\(n\)的正整数数组,执行以下操作严格一次。选择\(l,r,(1\leql<r\leqn)\),任意一个正整数\(k\)。重复\(k\)次:让\([l,r]\)的数组成环,按顺时针走一次。希望\(a_n-a_1\)最大,找到这个数。分类讨论题。先判断\(n\)为\(1\)时\(a_n-a_1\)......
  • Codeforces Round 830 (Div. 2) B. Ugu
    给一个\(01\)字符串,需要使它变为非降的,可以执行以下操作:选择一个下标\(i,(1\leqi\leqn)\),\(\forallj\geqi\)的数位翻转。经典的按无后效性翻转问题。考虑从前往后,得到一个全\(0\)串。若开始存在\(1\),则答案减\(1\)。如果存在\(1\),遇到\(1\)便翻转后......
  • $Codeforces Round 891 (Div. 3)$
    \(A.ArrayColoring\)显然需要奇数个偶数即可满足题目。voidsolve(){intn=read(),res=0;for(inti=1;i<=n;i++){intx=read();if(x%2)res++;}puts(res%2==0?"YES":"NO");//puts(ans>0?"Yes":"No&......