首页 > 其他分享 >[NOIP2022] 比赛 - 总结

[NOIP2022] 比赛 - 总结

时间:2023-11-12 22:22:50浏览次数:33  
标签:总结 比赛 cdot axy ay cy cx NOIP2022 ax

[NOIP2022] 比赛

0.问题转化

首先需要转化为区间历史和问题。

具体上来讲,就是将询问离线后,扫描线维护对于 \(r\) 来说,每一个 \(l\) 的 \(\sum_{i=l}^{r}(\max_{j=l}^{i}a_j\ \cdot\ \max_{j=l}^{i}b_j)\)

那么答案就是区间和。

1.构造信息与标记

接下来就是如何维护区间历史和

问题就在于如何构造合适的 信息(\(M\)) 与 标记(\(T\))。

\(M,T\) 应当是封闭的。

观察我们的问题,实际上就是每次 \(S\gets S+X\cdot Y\),具体的 \(X,Y\) 显然的应当使用单调栈来维护,那么每次我们都要将一部分 \(X,\ Y\) 覆盖。

\(M\) 中的内容我们至少就需要来维护 \(S,X,Y,X\cdot Y\) 了,即 \(s, x, y, xy\)。

\(T\) 中的内容呢?我们需要 \(X,Y,X\cdot Y\) 的系数,\(X,Y\) 的覆盖标记,以及一个常数 \(A\)。即 \(ax, ay, axy, cx, cy, a\)。

2.信息与标记的合并

那么我们设每次

\[\begin{aligned} s' & = s + ax \cdot x + ay \cdot y + axy \cdot xy + a \\ x' & = \begin{cases} cx, & \text{if } cx \ne 0 \\ x, & \text{if } cx = 0 \\ \end{cases} \\ y' & = \begin{cases} cy, & \text{if } cy \ne 0 \\ y, & \text{if } cy = 0 \\ \end{cases} \end{aligned} \]

2.0.信息之间的合并

信息的合并是简单的,即

msg operator + (const msg &g) const { return msg(s + g.s, x + g.x, y + g.y, xy + g.xy); }
2.1.标记与信息之间的合并

标记作用于信息也是较简单的,即

struct tag {
    u64 a, cx, cy, ax, ay, axy;
    // ......
	msg apply(msg g, u64 len) {
		g.s += g.x * ax + g.y * ay + g.xy * axy + a * len;
		if (cx && cy) g.x = cx * len, g.y = cy * len, g.xy = cx * cy * len;
		else if (cx) g.x = cx * len, g.xy = cx * g.y;
		else if (cy) g.y = cy * len, g.xy = cy * g.x;
		return g;
	}
};
2.2.标记之间的合并

难点在于如何合并标记,假设是 \(T_1\) 作用到 \(T_0\) 上。

  1. \(T_0.cx,T_0.cy\) 都有值:

    \[\begin{aligned} &\begin{cases} s_0&=s+ax_0\cdot x+ay_0\cdot y+axy_0\cdot xy+a_0\\ s_1&=s_0+ax_1\cdot x_0+ay_1\cdot y_0+axy_1\cdot x_0y_0+a_1\\ \end{cases}\\ &s_1 = s+ax_0\cdot x+ay_0\cdot y+axy_0\cdot xy+a_0+ax_1\cdot x_0+ay_1\cdot y_0+axy_1\cdot x_0y_0+a_1\\ \end{aligned} \]

    观察到 \(T_0.cx,T_0.cy\) 就是 \(x_0,y_0\),那么我们可以直接将 \(ax_1\cdot x_0+ay_1\cdot y_0+axy_1\cdot x_0y_0\) 算出来,加到常数项上。

  2. 只有 \(T_0.cx\) 有值:

    \[\begin{aligned} &\begin{cases} s_0&=s+ax_0\cdot x+ay_0\cdot y+axy_0\cdot xy+a_0\\ s_1&=s_0+ax_1\cdot x_0+ay_1\cdot y+axy_1\cdot x_0y+a_1\\ \end{cases}\\ &\begin{aligned} s_1&=s+ax_0\cdot x+ay_0\cdot y+axy_0\cdot xy+a_0+ax_1\cdot x_0+ay_1\cdot y+axy_1\cdot x_0y+a_1\\ &=s+ax_0\cdot x+(ay_0+ay_1+axy_1\cdot x_0)\cdot y+axy_0\cdot xy+a_0+ax_1\cdot x_0+a_1 \end{aligned} \end{aligned} \]

    将 \(ay_0+ay_1+axy_1\cdot x_0\) 作为新的 \(ay\),\(ax_1\cdot x_0\) 加到常数项上。

  3. 只有 \(T_0.cy\) 有值:

    与上同理。

  4. \(T_0.cx,T_0.cy\) 都没有值:

    \[\begin{aligned} &\begin{cases} s_0&=s+ax_0\cdot x+ay_0\cdot y+axy_0\cdot xy+a_0\\ s_1&=s_0+ax_1\cdot x+ay_1\cdot y+axy_1\cdot xy+a_1\\ \end{cases}\\ &\begin{aligned} s_1&=s+ax_0\cdot x+ay_0\cdot y+axy_0\cdot xy+a_0+ax_1\cdot x+ay_1\cdot y+axy_1\cdot xy+a_1\\ &=s+(ax_0+ax_1)\cdot x+(ay_0+ay_1)\cdot y+(axy_0+axy_1)\cdot xy+a_0+a_1 \end{aligned} \end{aligned} \]

    对应的系数进行对应的修改即可。

struct tag {
	u64 a, cx, cy, ax, ay, axy;
	// ......
	tag operator + (const tag &g) const {
		tag r = *this;
		r.a += g.a;
		if (r.cx && r.cy) r.a += g.axy * r.cx * r.cy + g.ax * r.cx + g.ay * r.cy;
		else if (r.cx) r.a += g.ax * r.cx, r.ay += g.ay + g.axy * r.cx;
		else if (r.cy) r.a += g.ay * r.cy, r.ax += g.ax + g.axy * r.cy;
		else r.axy += g.axy, r.ax += g.ax, r.ay += g.ay;
		if (g.cx) r.cx = g.cx;
		if (g.cy) r.cy = g.cy;
		return r;
	}
};

3.代码

剩下的做正常的线段树即可。

#include <bits/stdc++.h>

using namespace std;

typedef long long i64;
typedef unsigned long long u64;

template<typename T> inline void in(T &s) {
	char c = getchar(); int f = 1; s = 0;
	while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); }
	while (isdigit(c)) s = (s << 3) + (s << 1) + (c ^ 48), c = getchar();
	if (f < 0) s = -s;
}

const int N = 250005, P = 1000005;

struct msg {
	u64 s, x, y, xy;
	
	msg(): s(0), x(0), y(0), xy(0) {}
	msg(u64 _s, u64 _x, u64 _y, u64 _xy): s(_s), x(_x), y(_y), xy(_xy) {}
	
	msg operator + (const msg &g) const { return msg(s + g.s, x + g.x, y + g.y, xy + g.xy); }
};
struct tag {
	u64 a, cx, cy, ax, ay, axy;
	
	tag(): a(0), cx(0), cy(0), ax(0), ay(0), axy(0) {}
	tag(u64 _cx, u64 _cy, u64 _a, u64 _ax, u64 _ay, u64 _axy): a(_a), cx(_cx), cy(_cy), ax(_ax), ay(_ay), axy(_axy) {}
	
	tag operator + (const tag &g) const {
		tag r = *this;
		r.a += g.a;
		if (r.cx && r.cy) r.a += g.axy * r.cx * r.cy + g.ax * r.cx + g.ay * r.cy;
		else if (r.cx) r.a += g.ax * r.cx, r.ay += g.ay + g.axy * r.cx;
		else if (r.cy) r.a += g.ay * r.cy, r.ax += g.ax + g.axy * r.cy;
		else r.axy += g.axy, r.ax += g.ax, r.ay += g.ay;
		if (g.cx) r.cx = g.cx;
		if (g.cy) r.cy = g.cy;
		return r;
	}
	
	bool empty() { return !(a || cx || cy || ax || ay || axy); }	
	
	msg apply(msg g, u64 len) {
		g.s += g.x * ax + g.y * ay + g.xy * axy + a * len;
		if (cx && cy) g.x = cx * len, g.y = cy * len, g.xy = cx * cy * len;
		else if (cx) g.x = cx * len, g.xy = cx * g.y;
		else if (cy) g.y = cy * len, g.xy = cy * g.x;
		return g;
	}
};

msg m[P];
tag t[P];

void pu(int o) { m[o] = m[o << 1] + m[o << 1 | 1]; }
void down(int o, int l, int r, tag w) { m[o] = w.apply(m[o], r - l + 1), t[o] = t[o] + w; }
void pd(int o, int l, int r) {
	if (t[o].empty()) return ;
	int mid = (l + r) >> 1;
	down(o << 1, l, mid, t[o]);
	down(o << 1 | 1, mid + 1, r, t[o]);
	t[o] = tag();
}
void upd(int o, int l, int r, int u, int v, tag w) {
	if (u <= l && r <= v) return down(o, l, r, w);
	int mid = (l + r) >> 1;
	pd(o, l, r);
	if (u <= mid) upd(o << 1, l, mid, u, v, w);
	if (v > mid) upd(o << 1 | 1, mid + 1, r, u, v, w);
	pu(o);
}
msg qry(int o, int l, int r, int u, int v) {
	if (u <= l && r <= v) return m[o];
	int mid = (l + r) >> 1; msg ans;
	pd(o, l, r);
	if (u <= mid) ans = ans + qry(o << 1, l, mid, u, v);
	if (v > mid) ans = ans + qry(o << 1 | 1, mid + 1, r, u, v);
	pu(o);
	return ans;
}

int n, q;
u64 a[N], b[N], ans[N];
vector<pair<int, int>> que[N];

struct sta {
	int h; pair<u64, int> s[N];
	
	sta() {}
	
	void pop(u64 x) { while (h && s[h].first <= x) --h; }
	void push(u64 x, int y) { s[++h] = make_pair(x, y); }
	int top() { return s[h].second; }
} A, B;

int main() {
	int T; in(T);
	in(n);
	for (int i = 1; i <= n; ++i) in(a[i]);
	for (int i = 1; i <= n; ++i) in(b[i]);
	in(q);
	for (int i = 1; i <= q; ++i) {
		int l, r; in(l), in(r);
		que[r].emplace_back(make_pair(l, i));
	}
	for (int i = 1; i <= n; ++i) {
		A.pop(a[i]), B.pop(b[i]);
		upd(1, 1, n, A.top() + 1, i, tag(a[i], 0, 0, 0, 0, 0));
		upd(1, 1, n, B.top() + 1, i, tag(0, b[i], 0, 0, 0, 0));
		upd(1, 1, n, 1, i, tag(0, 0, 0, 0, 0, 1));
		A.push(a[i], i), B.push(b[i], i);
		for (auto j : que[i]) {
			int l, id; tie(l, id) = j;
			ans[id] = qry(1, 1, n, l, i).s;
		}
	}
	for (int i = 1; i <= q; ++i) printf("%llu\n", ans[i]);
	return 0;
}

标签:总结,比赛,cdot,axy,ay,cy,cx,NOIP2022,ax
From: https://www.cnblogs.com/FUXyao/p/17828003.html

相关文章

  • 2023-2024-1 20231418 《计算机基础与程序设计》第七周周总结
    2023-2024-120231418《计算机基础与程序设计》第七周总结作业信息这个作业属于哪个课程<班级的链接>(2023-2024-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(2023-2024-1计算机基础与程序设计第七周作业这个作业的目标数组与链表、基于数组和基于链......
  • 2023-2024-1 20231413 《计算机基础与程序设计》第七周学习总结
    2023-2024-120231413《计算机基础与程序设计》第七周学习总结1.作业信息班级:2023-2024-1-计算机基础与程序设计作业要求:2023-2024-1《计算机基础与程序设计》教学进程目标:自学教材:计算机科学概论第8章并完成云班课测试《C语言程序设计》第6章并完成云班课测试作业正文:h......
  • 第十一周 Linux课后技术总结
    6.2进程管道管道的作用是把上一个进程的输出作为下一个进程的输入,利用管道可以把若干个命令连接在一起。【例1】将/etc/passwd中的用户按UID数值大小排序并显示前三行。【例2】统计出最占CPU的5个进程。第七章存储管理7.1存储方式从连接方式上,存储分为以下三种......
  • 《2023-2024-1 202324《网络空间安全导论》第十一周学习总结》
    《2023-2024-1202324《网络空间安全导论》第十一周学习总结》教材学习内容总结本周学习了《网络空间安全导论》的第一章,着重学习了网络空间安全的概念与内涵,我国关于网络空间安全的法律法规,信息安全标准等内容。由于对于这门课的了解不够深刻,知识要点不清晰,好像就只是看了一遍......
  • rustbook-ch1-入门指南-总结
    rustbook-ch1-入门指南-总结1、安装rust之前需要安装一个C语言编译器。正常编译、执行rust程序,需要一个链接器。由于C语言编译器通常都会附带链接器,所以需要安装一个C语言编译器。除了编译执行需要链接器外,一部分常用的Rust包会依赖使用C语言编写的代码,为了编译这些Rust代码,也需......
  • 2023-2024-1 20231407陈原《计算机科学与概论》与《C语言程序设计》第七周学习总结
    这个作业属于哪里?2023-2024计算机基础与程序设计作业要求是什么?https://www.cnblogs.com/rocedu/p/9577842.html#WEEK07作业目的是什么计算机科学概论第8章《C语言程序设计》第6章作业正文  https://www.cnblogs.com/CCCY12345/p/17827874.html学习了程序中......
  • 2023-2024-1 20231325 《计算机基础与程序设计》第7周学习总结
    ###目录*作业信息*教材学习内容总结1.《计算机科学概论》第8章2.《c语言程序设计》第6章*基于AI的学习*学习心得*学习进度条作业信息这个作业属于哪个课程2023-2024-1《计算机基础与程序设计》这个作业的要求在哪里1.学习《计算机科学概论》第8章并完成......
  • 2023-2024-1 20231321 《计算机基础与程序设计》第7周学习总结
    2023-2024-120231321《计算机基础与程序设计》第7周学习总结作业信息这个作业属于哪个课程https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP这个作业要求在哪里https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP/homework/13003这个作业的目标《计......
  • 2023-2024-1 学号:20231305 《计算机基础与程序设计》第7周学习总结
    2023-2024-1学号:20231305《计算机基础与程序设计》第7周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2022-2023-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(如2022-2023-1计算机基础与程序设计第一周作业)这个作业的目标<自学教材计算......
  • 学年(2023-2024-1)学号(20231311)《计算机基础与程序设计》第7周学习总结
    2023-2024-120231311《计算机基础与程序设计》第7周学习总结作业信息这个作业属于哪个课程2023-2024-1-计算机基础与程序设计这个作业要求在哪里2023-2024-1计算机基础与程序设计第七周作业这个作业的目标1.学习计算机科学概论第8章并完成云班课测试2.《C语言程......