2023/11/15 NOIP 模拟赛
T1 游戏
标签
尺取 线段树 单调队列
线段树进阶
思路
抽象题意,相当于有 \(t\) 个点,有 \(n\) 个下接 \(x\) 轴的矩形。
首先明显可以按照 \(c\) 排序,然后尺取。
写法
线段树记录每区间内未被覆盖的最大高度。
因为插入和删除的顺序相对不变,一个单调队列维护该区间内矩形高度即可,若有删除操作则向儿子取 \(\max\) 重新计算 \(mx\)。
代码
常数极大,可使用内存池优化。
code
ci N = 1e6 + 9;
ci inf = 2e9;
int t, n, ans(inf);
int a[N], b[N], c[N], v[N], h[N], id[N];
bool cmp(int x, int y) {return c[x] < c[y];}
struct SGT {
	#define lc ((u) << 1)
	#define rc ((u) << 1 | 1)
	int mx[N << 2], buf[N * 40];
	unsigned int head[N << 2], tail[N << 2];
	il void pushup_mx(int u) {
		if(head[u] > tail[u]) return;
		if(v[q[u][head[u]]] >= mx[u]) mx[u] = 0;
	}
	il void pushup(int u) {
		mx[u] = max(mx[lc], mx[rc]);
		pushup_mx(u);
	}
	il void build(int u, int l, int r) {
		if(l == r) return mx[u] = h[l], void();
		int mid = (l + r) >> 1;
		build(lc, l, mid);
		build(rc, mid + 1, r);
		pushup(u);
	}
	il void insert(int u, int l, int r, int a, int b, int i) {
		if(a <= l && r <= b) {
			while(head[u] < q[u].size() && v[*(-- q[u].end())] <= v[i]) q[u].pop_back();
			q[u].eb(i);
			if(v[q[u][head[u]]] >= mx[u]) mx[u] = 0;
			return;
		}
		if(b < l || r < a) return;
		int mid = (l + r) >> 1;
		insert(lc, l, mid, a, b, i);
		insert(rc, mid + 1, r, a, b, i);
		pushup(u);
	}
	il void erase(int u, int l, int r, int a, int b, int i) {
		if(a <= l && r <= b) {
			if(q[u][head[u]] == i) {
				++ head[u];
				if(l == r) {
					mx[u] = h[l];
					pushup_mx(u);
				}
				else {
					pushup(u);
				}
			}
			return;
		}
		if(b < l || r < a) return;
		int mid = (l + r) >> 1;
		erase(lc, l, mid, a, b, i);
		erase(rc, mid + 1, r, a, b, i);
		pushup(u);
	}
} tree;
il void ins(int i) {
	tree.insert(1, 1, t, a[i], b[i], i);
}
il void ers(int i) {
	tree.erase(1, 1, t, a[i], b[i], i);
}
int main() {
	freopen("game.in", "r", stdin);
	freopen("game.out", "w", stdout);
	rd(t); rd(n);
	rep(i, 1, n) {
		rd(a[i], b[i], c[i], v[i]);
		id[i] = i;
	}
	sort(id + 1, id + n + 1, cmp);
	rep(i, 1, t) rd(h[i]);
	tree.build(1, 1, t);
	int L = 1;
	rep(_i, 1, n) {
		int i = id[_i];
		ins(i);
		while(tree.mx[1] == 0) {
			cmin(ans, c[i] - c[id[L]]);
			ers(id[L]); ++ L;
		}
	}
	pt("%d\n", ans);
	return 0;
}
T2 驻军
标签
长链剖分,树上前缀和进阶
思路
订正的时候没有对答案取模再乘,dfs 时没有判长链。
考虑将找链转化为对端点处理,发现可以通过处理将答案变为只与 \(lca(x, y), x, y\) 有关的形式,这样才能进行长链剖分。
约定
\(f_u\) 表示 \(u\) 子树内所有点到 \(u\) 的距离和。
\(e_{u, v}\) 表示 \((u\to v)\) 的边权。
\(h_u\) 表示 \(u\) 子树外所有点到 \(u\) 的距离和。
\(sz_u\) 表示 \(u\) 子树的大小。
\(w_v\) 表示 \((fa_v\to v)\) 的贡献,等于 \(sz_v\cdot e_{fa_v, v}\)。
\(s_u\) 表示从 \(u\) 到根(可设为 \(1\))的简单路径上的边的 \(w\) 之和,等于 \(w_u + w_{fa_u} + \cdots\)
转移
若路径为 \(x, y\),设 \(lca(x, y) = u\) 则答案为 \(h_u + f_u - (s_x - s_u) - (s_y - s_u)\)。
这个比较难,可对每条边快速统计多算的贡献,减去即可。
\(f_u = \sum\limits_{u\to v} (f_v + w_v)\)
\(s_v = s_u + w_v\)
\(h_v = (n - sz_v)\cdot e_{u, v} + h_u + f_u - f_v - w_v\)
代码
code
ci N = 2e6 + 9;
const ll INF = 1e18;
int n, k;
ll sz[N], f[N], s[N], h[N], w[N];
vector<pii> A[N];
void dfs1(int u, int la) {
	sz[u] = 1;
	for(pii e : A[u]) {
		int v = e.fi;
		if(v == la) continue;
		dfs1(v, u);
		sz[u] += sz[v];
		w[v] = sz[v] * e.se;
		f[u] += f[v] + w[v];
	}
}
int depth[N], son[N];
void dfs2(int u, int la) {
	depth[u] = 1;
	for(pii e : A[u]) {
		int v = e.fi;
		if(v == la) continue;
		s[v] = s[u] + w[v];
		h[v] = 1LL * (n - sz[v]) * e.se + h[u] + (f[u] - f[v] - w[v]);
		dfs2(v, u);
		cmax(depth[u], depth[v] + 1);
		if(depth[v] + 1 == depth[u]) son[u] = v;
	}
}
ll buc[N], *mx[N], ans(INF);
void dfs(int u, int la) {
	mx[u][1] = s[u];
	if(son[u]) {
		mx[son[u]] = mx[u] + 1;
		dfs(son[u], u);
		for(pii e : A[u]) {
			int v = e.fi;
			if(v == la || v == son[u]) continue;
			mx[v] = mx[u] + depth[u];
			dfs(v, u);
			rep(i, 1, depth[v]) {
				if(i > 0 && k - i > 1 && i <= depth[v] && k - i <= depth[u]) {
					cmin(ans, h[u] + f[u] + 2 * s[u] - mx[u][k - i] - mx[v][i]);
					if(ans < 0) {
						printf("%lld %lld %lld\n", h[u], f[u], s[u]);
						printf("u-road = %d v = %d\n", u, v), exit(0);
					}
				}
			}
			rep(i, 1, depth[v]) cmax(mx[u][i + 1], mx[v][i]), mx[v][i] = 0;
		}
	}
	if(depth[u] >= k) {
		cmin(ans, h[u] + f[u] + s[u] - mx[u][k]);
		if(ans < 0) printf("u-list = %d\n", u),exit(0);
	}
}
ci mod = 998244353;
ll fpow(ll a, ll x) {
	ll res = 1;
	while(x) {
		if(x & 1) res = res * a % mod;
		a = a * a % mod;
		x >>= 1;
	}
	return res;
}
int dis[N];
void _dfs(int u, int la) {
	dis[u] = dis[la] + 1;
	for(pii e : A[u]) {
		if(e.fi == la) continue;
		_dfs(e.fi, u);
	}
}
int main() {
    // freopen("barrack.in", "r", stdin);
    // freopen("barrack.out", "w", stdout);
    freopen("a.in", "r", stdin);
	rd(n, k);
	rep(i, 2, n) {
		int x, y, z;
		rd(x, y, z);
		A[x].eb(mp(y, z));
		A[y].eb(mp(x, z));
	}
	int st = 1;
	_dfs(1, 0);
	rep(i, 2, n) {
		if(dis[i] > dis[st]) {
			st = i;
		}
	}
	_dfs(st, 0);
	rep(i, 1, n) {
		if(dis[i] > dis[st]) {
			st = i;
		}
	}
	if(dis[st] < k) return puts("-1"), 0;
	dfs1(1, 0);
	dfs2(1, 0);
	mx[1] = buc;
	dfs(1, 0);
	printf("%lld\n", ans % mod * fpow(n, mod - 2) % mod);
	return 0;
}
T3 序列
标签
离线
线段树入门
思路
首先有 \(\gcd(x, x - v) = \gcd(x, x + v) = \gcd(x, v)\)
考虑将所有操作离线,对于每一个位置 \(i\) 处理询问。
第 \(j\) 次询问 \(p,k\) 相当于将 \(0\sim k - 1\) 的前缀和\(= a_i + \sum\limits_{q < k, i\in [l_q, r_q]} v_q\) 与 \(k\sim j\) 的 \(v\) 的 \(\gcd\) 求一个 \(\gcd\),开个线段树维护一下区间和和区间 \(\gcd\) 即可。
感觉比 T2 简单。
代码
代码好写。
code
ci N = 2.5e5 + 9;
int n, q;
int a0[N], qval[N], op[N];
ll ans[N];
vector<int> ins[N], ers[N];
vector<int> qry[N];
ll gcd(ll a, ll b) {return !b ? a : gcd(b, a % b);}
struct SGT {
	#define lc ((u) << 1)
	#define rc ((u) << 1 | 1)
	int tr_gcd[N << 2];
	ll tr_sum[N << 2];
	void push_up(int u) {
		tr_sum[u] = tr_sum[lc] + tr_sum[rc];
		tr_gcd[u] = gcd(tr_gcd[lc], tr_gcd[rc]);
	}
	void modify(int u, int l, int r, int loc, int var) {
		if(l == r) {
			tr_gcd[u] = tr_sum[u] = var;
			return;
		}
		int mid = (l + r) >> 1;
		if(loc <= mid) modify(lc, l, mid, loc, var);
		else modify(rc, mid + 1, r, loc, var);
		push_up(u);
	}
	ll querysum(int u, int l, int r, int a, int b) {
		if(a <= l && r <= b) return tr_sum[u];
		if(b < l || r < a) return 0;
		int mid = (l + r) >> 1;
		return querysum(lc, l, mid, a, b) + querysum(rc, mid + 1, r, a, b);
	}
	int querygcd(int u, int l, int r, int a, int b) {
		if(a <= l && r <= b) return tr_gcd[u];
		if(b < l || r < a) return 0;
		int mid = (l + r) >> 1;
		return gcd(querygcd(lc, l, mid, a, b), querygcd(rc, mid + 1, r, a, b));
	}
} tree;
int main() {
	freopen("sequence.in", "r", stdin);
	freopen("sequence.out", "w", stdout);
	rd(n, q);
	rep(i, 1, n) rd(a0[i]);
	rep(i, 1, q) {
		rd(op[i]);
		if(op[i] == 1) {
			int l, r; rd(l, r, qval[i]);
			ins[l].eb(i);
			ers[r + 1].eb(i);
		}
		else {
			int p; rd(p, qval[i]);
			qry[p].eb(i);
		}
	}
	rep(i, 1, n) {
		for(int j : ins[i]) {
			tree.modify(1, 1, q, j, qval[j]);
		}
		for(int j : ers[i]) {
			tree.modify(1, 1, q, j, 0);
		}
		for(int j : qry[i]) {
			ans[j] = gcd(a0[i] + tree.querysum(1, 1, q, 1, qval[j] - 1), tree.querygcd(1, 1, q, qval[j], j));
		}
	}
	rep(i, 1, q) {
		if(op[i] == 2) {
			printf("%lld\n", abs(ans[i]));
		}
	}
	return 0;
}
2023/11/15 NOIP 模拟赛的更多相关文章
- 11/1 NOIP 模拟赛
		
11.1 NOIP 模拟赛 期望得分:50:实际得分:50: 思路:暴力枚举 + 快速幂 #include <algorithm> #include <cstring> #in ...
 - 11.7 NOIP模拟赛
		
目录 2018.11.7 NOIP模拟 A 序列sequence(two pointers) B 锁lock(思路) C 正方形square(埃氏筛) 考试代码 B C 2018.11.7 NOIP模 ...
 - 【2019.7.15 NOIP模拟赛 T2】与非树(nand)(树形DP)
		
树形\(DP\) 实际上,这道题应该不是很难. 我们设\(f_{x,i,j}\)表示在以\(x\)为根的子树内,原本应输出\(i\),结果输出了\(j\)的情况数. 转移时,为了方便,我们先考虑与,再 ...
 - 【2019.7.15 NOIP模拟赛 T1】夹缝(mirror)(思维题)
		
思维题 此题应该是比较偏思维的. 假设一次反射后前进的距离是\(2^x(2y+1)\),则显然,它可以看做是前进距离为\(2^x\)的光线经过了\((2y+1)\)次反射,两者是等价的,甚至后者可能还 ...
 - 2022.11.15 NOIP2022 模拟赛十
		
炸弹威力 Source:洛谷 P6036. 记 \(f_{i,0/1}\) 表示第 \(i\) 个位置为 \(0/1\) 的答案个数,有 DP 转移: \[\begin{aligned} (1-p_i ...
 - NOIP模拟赛-2018.11.7
		
NOIP模拟赛 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 编译之前另存一份,听说如果敲 ...
 - NOIP模拟赛-2018.11.6
		
NOIP模拟赛 今天想着反正高一高二都要考试,那么干脆跟着高二考吧,因为高二的比赛更有技术含量(我自己带的键盘放在这里). 今天考了一套英文题?发现阅读理解还是有一些困难的. T1:有$n$个点,$m ...
 - NOIP模拟赛-2018.11.5
		
NOIP模拟赛 好像最近每天都会有模拟赛了.今天从高二逃考试跑到高一机房,然而高一也要考试,这回好像没有拒绝的理由了. 今天的模拟赛好像很有技术含量的感觉. T1:xgy断句. 好诡异的题目,首先给出 ...
 - contesthunter暑假NOIP模拟赛第一场题解
		
contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...
 - NOIP模拟赛 by hzwer
		
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
 
随机推荐
- Spring的AOP快速实现通用日志打印
			
需求分析 针对VideoService接口实现日志打印 三个核心包 spring-aop:AOP核心功能,例如代理工厂 aspectjweaver:简单理解,支持切入点表达式 aspectjrt:简单 ...
 - 教你基于MindSpore用DCGAN生成漫画头像
			
本文分享自华为云社区<[昇思25天学习打卡营打卡指南-第二十天]DCGAN生成漫画头像>,作者:JeffDing. DCGAN生成漫画头像 在下面的教程中,我们将通过示例代码说明DCGAN ...
 - 算法金 | 来了,pandas 2.0
			
大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今日 210+/10000,内含 Pandas 是一个强大的数据分析库,广泛应用于科学 ...
 - centos下安装Docker容器
			
安装前的准备工作 1.列出docker安装过的相关包 sudo yum list installed | grep docker 2.删除相关安装包 #根据查找出来的进行删除,不同版本可能有不一样的情 ...
 - 题解:P10672 【MX-S1-T1】壁垒
			
暑期集训=依托答辩. 分析 种类数是奇数一定无解. 否则每种数字先输出一次,在此过程中每增加两个数时,因为每个数字种类数都不一样,所以前缀种类数也同时增加 \(2\),保证一定为偶数. 然后输出完以后 ...
 - 使用 Node.js 和 Express 构建基本的 Web API
			
使用 Node.js 和 Express 构建 Web API Web API Node.js 中的 http 模块 创建 Express 框架 Web 应用程序 Express 框架 Express ...
 - python中pip安装包出现Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None))…………或无法pip install packname安装依赖包
			
问题: 安装包出现Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connec ...
 - 使用 useSeoMeta 进行 SEO 配置
			
title: 使用 useSeoMeta 进行 SEO 配置 date: 2024/7/30 updated: 2024/7/30 author: cmdragon excerpt: 摘要:本文介绍了 ...
 - Jmeter函数助手7-timeShift
			
timeShift函数用于获取移动时间变化后的指定格式时间. Format string for DateTimeFormatter (optional) (default unix timestam ...
 - 【Vue】未读消息标记功能
			
页面展示的效果如图,需要定时更新未读消息 首先是后台的接口,查询未处理的消息数量 因为是七张消息表,数据我需要合在一起返回给前台: 这里使用UNION连接各个表 SELECT COUNT(*) AS ...