首页 > 其他分享 >[Ynoi2013] D2T2 做题记录

[Ynoi2013] D2T2 做题记录

时间:2024-12-13 20:09:14浏览次数:3  
标签:10 const 记录 ll Ynoi2013 maxn define D2T2 mod

link

很厉害的题目。

先弱化题目,考虑 \(l = 1, r = n\) 怎么做。

设 \(f(x, y)\) 表示只保留值域在 \([a_x, a_y]\) 的数的最大子段和,有用状态数为 \(\mathcal O(n^2)\)。

我们发现这玩意其实是可以分治的:将原序列分成两半,求出左半部分和右半部分的只保留 \([a_x, a_y]\) 中的数的总和、最大前缀和、最大后缀和、最大子段和,合并是容易的。

这样时间复杂度为 \(T(n) = \mathcal O(n ^ 2) + 2T(\frac n2) = \mathcal O(n ^ 2)\)。

为了平衡复杂度,考虑分块,对于每块分治求出所有 \(f(x, y)\),然后每个询问再依次合并每个块的答案。

这十分容易拓展到 \([l, r]\) 一般的情况,时间复杂度 \(\mathcal O(n\sqrt n)\)。

  • 启示:弱化问题;分块平衡复杂度(不弱化不能从这个点入手);无脑尝试分块;半群的分治性质
点击查看代码
#include <bits/stdc++.h>

namespace Initial {
	#define ll int
	#define ull unsigned long long
	#define fi first
	#define se second
	#define mkp make_pair
	#define pir pair <ll, ll>
	#define pb emplace_back
	#define i128 __int128
	using namespace std;
	const ll maxn = 1e5 + 10, inf = 1e9, mod = 1e9 + 7;
	ll power(ll a, ll b = mod - 2) {
		ll s = 1;
		while(b) {
			if(b & 1) s = 1ll * s * a %mod;
			a = 1ll * a * a %mod, b >>= 1;
		} return s;
	}
	template <class T>
	const ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void chkmax(T &x, const T y) { x = x < y? y : x; }
	template <class T>
	void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;

namespace Read {
	char buf[1 << 22], *p1, *p2;
	#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
	template <class T>
	void rd(T &x) {
		char ch; bool neg = 0;
		while(!isdigit(ch = getchar()))
			if(ch == '-') neg = 1;
		x = ch - '0';
		while(isdigit(ch = getchar()))
			x = (x << 1) + (x << 3) + ch - '0';
		if(neg) x = -x;
	}
} using Read::rd;

namespace Fwrite {
	const int BUFFER_SIZE = 1 << 22, N = 15 + 7;
	char buffer[BUFFER_SIZE + 7], temp[N];
	char *p = buffer;
	
	inline void flush(){
		fwrite(buffer, p - buffer, 1, stdout);
		p = buffer;
	}
	
	inline void putchar(char ch){
		if (p - buffer >= BUFFER_SIZE) flush();
		*p++ = ch;
	}
	
	inline void write(long long x){
		int top = 0;
		do {
			temp[top++] = x % 10 + '0';
			x /= 10;
		} while (x > 0);
		while (top-- > 0) putchar(temp[top]);
	}
}

const ll B = 220;
ll n, m, a[maxn], ql[maxn], qr[maxn], qL[maxn], qR[maxn];
ll b[B + 10], id[B + 10], _id[B + 10], h[maxn], ht, _a[maxn];

struct Data { long long res, pre, suf, sum; }
 d[B + 10][B + 10], _d[B + 10][B + 10], ans[maxn];
const Data operator + (const Data a, const Data b) {
	return (Data) { max(max(a.res, b.res), a.suf + b.pre),
	 max(a.pre, a.sum + b.pre), max(b.suf, a.suf + b.sum), a.sum + b.sum };
}

void solve(const ll l, const ll r) {
	if(l == r) {
		ll w = max(0, b[l]);
		d[l][l] = (Data) { w, w, w, b[l] }; return;
	} const ll mid = l + r >> 1;
	solve(l, mid), solve(mid + 1, r);
	ll o1 = l, o2 = mid + 1, o = l;
	while(o1 <= mid || o2 <= r) {
		if(o1 <= mid && (o2 > r || b[id[o1]] <= b[id[o2]]))
			_id[o++] = id[o1++];
		else _id[o++] = id[o2++];
	}
	for(register ll i = l; i <= r; i = -~i) id[i] = _id[i];
	for(register ll i = l; i <= r; i = -~i) {
		const ll c = id[i]; auto p = _d[c];
		ll l_st = 0, l_ed = 0, r_st = 0, r_ed = 0;
		for(ll j = i; j <= r; j = -~j) {
			const ll x = id[j];
			if(x <= mid)  l_ed = x, !l_st && (l_st = x);
			else  r_ed = x, !r_st && (r_st = x);
			if(l_st && r_st)
				p[x] = d[l_st][l_ed] + d[r_st][r_ed];
			else p[x] = l_st? d[l_st][l_ed] : d[r_st][r_ed];
		}
	}
	for(register ll i = l; i <= r; i = -~i)
		for(register ll j = l; j <= r; j = -~j) d[i][j] = _d[i][j];
}
ll f[maxn], g[maxn];

int main() {
//	freopen("p.in", "r", stdin);
//	freopen("p.out", "w", stdout);
	rd(n), rd(m);
	for(register ll i = 1; i <= n; i = -~i) rd(a[i]), h[++ht] = a[i];
	sort(h + 1, h + 1 + ht);
	ht = unique(h + 1, h + 1 + ht) - h - 1;
	for(register ll i = 1; i <= m; i = -~i) {
		rd(ql[i]), rd(qr[i]), rd(qL[i]), rd(qR[i]);
		qL[i] = lower_bound(h + 1, h + 1 + ht, qL[i]) - h;
		qR[i] = upper_bound(h + 1, h + 1 + ht, qR[i]) - h - 1;
	}
	for(register ll i = 1; i <= n; i = -~i)
		_a[i] = lower_bound(h + 1, h + 1 + ht, a[i]) - h;
	for(register ll u = 1; (u - 1) * B < n; u = -~u) {
//		if(2 * u * B > n) return 0;
		const ll ul = (u - 1) * B + 1, ur = min(n, u * B);
		for(ll i = 0; i <= ur - ul; i++)
			b[i + 1] = a[ul + i], id[i + 1] = i + 1;
		solve(1, ur - ul + 1);
		memset(f, 0, sizeof f), memset(g, 0, sizeof g);
		for(register ll i = 1; i <= ur - ul + 1; i = -~i)
			f[_a[ul - 1 + id[i]]] = id[i];
		for(ll i = ur - ul + 1; i; i--)
			g[_a[ul - 1 + id[i]]] = id[i];
		for(register ll i = 1; i <= ht; i = -~i) !f[i] && (f[i] = f[i - 1]);
		for(register ll i = ht; i; i--) !g[i] && (g[i] = g[i + 1]);
		for(register ll i = 1; i <= m; i = -~i)
			if(ql[i] <= ul && ur <= qr[i]) {
				ll x = g[qL[i]], y = f[qR[i]];
				if(b[x] <= b[y])
					ans[i] = ans[i] + d[x][y];
			}
			else {
				ll x = max(ql[i], ul), y = min(qr[i], ur);
				if(x > y) continue;
				for(ll j = x; j <= y; j = -~j)
					if(_a[j] >= qL[i] && _a[j] <= qR[i]) {
						ans[i].suf = max(ans[i].suf + a[j], 0ll);
						ans[i].res = max(ans[i].res, ans[i].suf);
						ans[i].sum += a[j];
						ans[i].pre = max(ans[i].pre, ans[i].sum);
					}
			}
	}
	for(ll i = 1; i <= m; i++) Fwrite::write(ans[i].res), Fwrite::putchar('\n');
	Fwrite::flush();
	return 0;
}

标签:10,const,记录,ll,Ynoi2013,maxn,define,D2T2,mod
From: https://www.cnblogs.com/Sktn0089/p/18605772

相关文章

  • [Ynoi2010] Brodal queue 做题记录
    link加深了对分块算法的理解。题目相当于求解一个区间内每种颜色出现次数平方和,这种题显然无法polylog。先尝试分块,将贡献拆成散块-散块;散块-整块;整块-整块三种。散块-散块是容易的,直接用桶计数就好。整块-整块:设\(d_{c,i}\)表示颜色\(c\)在前\(i\)个块......
  • [Ynoi2000] tmostnrq 做题记录
    link先离线扫描线,相当于在\(l\)这个时刻加入一个点,然后每次令所有点向某个点的方向移动一步,在\(r\)时刻查询某个点的位置。以\(1\)为根,对于\(a_i\)相当于令\(1\toa_i\)这条链上所有点向下移动一步,其他点向上移动一步。我们需要同时支持这两种操作,但是不能每个点暴力......
  • 记录_信号完整性上机报告
    《信号完整性》实验报告实验工程图:2.1阻抗突变处的反射:一、实验目的本实验旨在研究信号在遇到传输线阻抗突变时产生的反射现象。通过设置不同阻抗的传输线,模拟和分析信号反射系数的变化,观察反射对信号波形的影响。实验的核心目标是理解阻抗突变如何影响信号传播,计算反射系数,......
  • 工作CASE_1 Hold Lot 已经Release但是Hold记录为空
    说明:DWT_HOLD_LOT的HoldLotHoldEvent('Hold','EditHoldComment','Release'),且每个Event都为一条记录,每条记录都有对应的RELEASE_EVENT_TIME,HOLD_SYS_ID,HOLD_RELEASEHOLDLOT已经Release,但是对应HOLD记录的Release时间是空的SELECT*FROMDWT_HOLD_LOTdhlW......
  • Linux 常用命令 日常工作记录 学习记录
     命令解释示例cd/opt/**/** 跳转目录 cd- 回到上一次目录 ping**.com 测试网络pingbaidu.comcal查看日历calssh 10.64.**.**跳转到其他服务器ssh10.64.1.1tail-ftest.log查看日志文件,并持续输出 ps-ef|grepjava查看......
  • 微信聊天记录中过期文件的找回方法
    在使用微信的过程中,我们经常会收到各种文件,如图片、视频、文档等。然而,有时由于种种原因,这些文件可能会过期,导致我们无法直接打开或下载。那么,当微信聊天记录中的文件过期时,我们还能通过哪些方法找回它们呢?本文将为您详细介绍几种实用的找回过期微信文件的方法。一、利用微信......
  • 记录一个困扰两天的问题:git 换行符LF与CRLF转换问题
    此篇文章在2023年11月27日被记录1、背景这两天在维护公司一个老旧项目,编译是用bat批处理+python实现的,但是把最新的代码拉下来后发现编译不过去,提示bat指令有错误,并且是很离谱的错误,但是回退到之间的稳定版本,命令行编译是没有任何问题的,经过两天N多次试错失败后终于发现了一些......
  • QT日志类SimpleQtLogger的简单记录
    在现代软件开发中,日志记录是必不可少的部分。它不仅帮助开发者在调试和维护软件时了解程序的运行状态,还能提供关键的错误信息。对于使用Qt框架开发应用程序的开发者来说,选择一个合适的日志库至关重要。本文将详细介绍Qt日志库SimpleQtLogger的特点、安装方法、使用示例以及它在实......
  • 记录一个开源的物理引擎:Physac
    此篇文章在2023年7月27日被记录1、Physac介绍Physac是一个开源的物理引擎,所有代码实现在头文件中,仅仅有2100行代码,移植接口只需要一个画线函数,因此很容易移植到嵌入式设备等,GitHub地址为https://github.com/victorfisac/Physac2、引擎接口引擎具有以下特性:可以动态创建\销......
  • 日常打靶Vulnhub靶场之Ubuntu_CTF过程记录
    靶场环境靶机:VirtualBox虚拟机主机(IP:192.168.56.17),网卡类型Host_only测试机:kalilinux(IP:192.168.56.3),网卡类型Host_only端口扫描nmap对靶机端口扫描,发现只开放了80、3306和33060三个端口。nmap-sT--min-rate10000-p-192.168.56.17继续对端口进行详细信息扫......