首页 > 其他分享 >[Ynoi2000] tmostnrq 做题记录

[Ynoi2000] tmostnrq 做题记录

时间:2024-12-13 19:33:00浏览次数:9  
标签:return tmostnrq 记录 ll Ynoi2000 maxn const void mod

link

先离线扫描线,相当于在 \(l\) 这个时刻加入一个点,然后每次令所有点向某个点的方向移动一步,在 \(r\) 时刻查询某个点的位置。

以 \(1\) 为根,对于 \(a_i\) 相当于令 \(1\to a_i\) 这条链上所有点向下移动一步,其他点向上移动一步。

我们需要同时支持这两种操作,但是不能每个点暴力跳,可以考虑树链剖分这两个方面。

容易想到打关于深度的标记。然后我们可以将操作视为:先令 \(1\to a_i\) 所有点向下移动一步,然后给这些点打上深度 \(+1\) 标记,最后给全局所有点打上深度 \(-1\) 标记。

若一个点根据其深度标记走出了所在重链,考虑暴力修改,不难发现一个点至多出现 \(\mathcal O(\log n)\) 次这种情况,快速找到这样的点可以用线段树维护所有重链中距离顶部最近的点的距离。

所有点向下移动同理,当多个点同时到达一个点时,考虑使用并查集将他们合并,这样保证了向下移动的时间正确性。

考虑使用平衡树,可以支持重链某一上半部分的点向下移动,快速判断是否有点重合,时间复杂度 \(\mathcal O(n\log ^ 2n)\)。

点击查看代码
#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 <int, int>
	#define pb emplace_back
	#define i128 __int128
	using namespace std;
	const ll maxn = 1e6 + 10, inf = 1e9, mod = 998244353;
	ll power(ll a, ll b = mod - 2) {
		ll s = 1;
		while(b) {
			if(b & 1) s = s * a %mod;
			a = a * a %mod, b >>= 1;
		} return s;
	}
	template <class T>
	const inline ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
	template <class T>
	const inline void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
	template <class T>
	const inline void chkmax(T &x, const T y) { x = x < y? y : x; }
	template <class T>
	const inline 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>
	const inline 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;

ll n, n0, m, top[maxn], siz[maxn], son[maxn], dfn[maxn], ti, a[maxn];
ll fa[maxn], tag[maxn], topdep[maxn], tpid[maxn], Tpid, _tp[maxn];
ll qL[maxn], qR[maxn], qS[maxn], ans[maxn], T, pos[maxn], dep[maxn];
vector <ll> to[maxn], vecL[maxn], vecR[maxn], pf[maxn];

void dfs1(ll u) {
	siz[u] = 1, dep[u] = dep[fa[u]] + 1;
	for(ll v: to[u]) {
		dfs1(v), siz[u] += siz[v];
		if(siz[v] > siz[son[u]]) son[u] = v;
	}
}
void dfs2(ll u, ll tp = 1) {
	top[u] = tp, dfn[u] = ++ti, topdep[u] = dep[u] - dep[top[u]];
	if(u == tp) tpid[u] = ++Tpid, _tp[Tpid] = u;
	else tpid[u] = tpid[tp]; pf[tpid[u]].pb(u);
	if(son[u]) dfs2(son[u], tp);
	for(ll v: to[u])
		if(v ^ son[u]) dfs2(v, v);
}

mt19937 rnd(20090623);
namespace Treap {
	struct node { ll lc, rc, w, rnd_val; } b[maxn];
	ll tot, d[maxn], tag[maxn], rt[maxn], Fa[maxn];
	ll find(ll x) { return d[x] ^ x? d[x] = find(d[x]) : x; }
	void addtag(ll p, ll v) { if(p) tag[p] += v, b[p].w += v; }
	void pushdown(ll p) {
		addtag(b[p].lc, tag[p]);
		addtag(b[p].rc, tag[p]);
		tag[p] = 0;
	}
	ll Findnode(ll p, ll w) {
		if(!p) return 0;
		if(b[p].w == w) return p; pushdown(p);
		if(w < b[p].w) return Findnode(b[p].lc, w);
		return Findnode(b[p].rc, w);
	}
	ll Merge(ll p, ll q) {
		if(!p || !q) return p | q;
		pushdown(p), pushdown(q); Fa[p] = Fa[q] = 0;
		if(b[p].rnd_val < b[q].rnd_val)
			return Fa[b[p].rc = Merge(b[p].rc, q)] = p;
		return Fa[b[q].lc = Merge(p, b[q].lc)] = q;
	}
	void Split(ll p, ll k, ll &x, ll &y) {
		if(!p) return x = y = 0, void();
		pushdown(p), Fa[p] = 0;
		if(b[p].w <= k)
			x = p, Split(b[p].rc, k, b[x].rc, y), Fa[b[x].rc] = x;
		else y = p, Split(b[p].lc, k, x, b[y].lc), Fa[b[y].lc] = y;
	}
	ll Getmin(ll p) {
		if(!p) return inf;
		if(b[p].lc) return pushdown(p), Getmin(b[p].lc);
		return b[p].w;
	}
	ll ask(ll p) {
		ll res = b[p].w;
		for(p = Fa[p]; p; p = Fa[p]) res += tag[p];
		return res;
	}
	void Insert(ll &p, ll now) {
		ll s1, s2; Split(p, b[now].w, s1, s2);
		p = Merge(Merge(s1, now), s2);
	}
} using namespace Treap;

struct SGT {
	pir mn[maxn << 2];
	void build(ll p, ll l, ll r) {
		mn[p] = mkp(inf, l);
		if(l == r) return; ll mid = l + r >> 1;
		build(p << 1, l, mid), build(p << 1|1, mid + 1, r);
	}
	void modify(ll p, ll l, ll r, ll x, ll v) {
		if(l == r) return mn[p].fi = v, void();
		ll mid = l + r >> 1;
		if(x <= mid) modify(p << 1, l, mid, x, v);
		else modify(p << 1|1, mid + 1, r, x, v);
		mn[p] = min(mn[p << 1], mn[p << 1|1]);
	}
} tr;

void upd(ll k) { tr.modify(1, 1, Tpid, k, Getmin(rt[k])); }

void Mov(ll u) {
	ll v = u; u = fa[u];
	while(u) {
		ll s1, s2; Split(rt[tpid[u]], topdep[u] + T, s1, s2);
		ll now; Split(s1, topdep[u] + T - 1, s1, now);
		addtag(s1, 1); rt[tpid[u]] = Merge(s1, s2);
		if(now) {
			b[now].w = topdep[v] + T; pos[now] = tpid[v];
			ll c = Findnode(rt[tpid[v]], b[now].w);
			if(c) d[now] = c;
			else Insert(rt[tpid[v]], now), upd(tpid[v]);
		}
		upd(tpid[u]), u = fa[v = top[u]];
	}
}

void tag_Mov(ll u) {
	while(u) {
		ll s1, s2; Split(rt[tpid[u]], topdep[u] + T, s1, s2);
		ll now; Split(s1, topdep[u] + T - 1, s1, now);
		addtag(s1, 1);
		if(now) {
			++b[now].w;
			ll c = Findnode(s2, b[now].w);
			if(c) d[now] = c, now = 0;
		} rt[tpid[u]] = Merge(Merge(s1, now), s2);
		upd(tpid[u]), u = fa[top[u]];
	}
}

ll getans(ll x) { return pf[pos[x]][ask(x) - T]; }

signed main() {
//	freopen("p.in", "r", stdin);
	rd(n), rd(n0), rd(m);
	for(ll i = 2; i <= n; i++) rd(fa[i]), to[fa[i]].pb(i);
	dfs1(1), dfs2(1);
	for(ll i = 1; i <= n0; i++) rd(a[i]);
	for(ll i = 1; i <= m; i++) {
		rd(qL[i]), rd(qR[i]), rd(qS[i]);
		vecL[qL[i]].pb(i), vecR[qR[i]].pb(i);
	} tr.build(1, 1, Tpid); tpid[0] = 1;
	for(ll i = 1; i <= n0; i++) {
		for(ll x: vecL[i]) {
			d[x] = x, b[x].w = topdep[qS[x]] + T;
			b[x].rnd_val = rnd();
			ll k = pos[x] = tpid[qS[x]];
			ll y = Findnode(rt[k], b[x].w);
			if(y) d[x] = y;
			else Insert(rt[k], x), upd(k);
		} Mov(a[i]);
		tag_Mov(a[i]), T = i;
		while(tr.mn[1].fi < T) {
			ll id = tr.mn[1].se;
			ll now; Split(rt[id], T - 1, now, rt[id]);
			ll u = fa[_tp[id]], _id = tpid[u];
			b[now].w = topdep[u] + T;
			pos[now] = _id;
			ll c = Findnode(rt[_id], b[now].w);
			if(c) d[now] = c;
			else Insert(rt[_id], now), upd(_id);
			upd(id);
		}
		for(ll j: vecR[i]) ans[j] = getans(find(j));
	}
	for(ll i = 1; i <= m; i++) printf("%d\n", ans[i]);
	return 0;
}

标签:return,tmostnrq,记录,ll,Ynoi2000,maxn,const,void,mod
From: https://www.cnblogs.com/Sktn0089/p/18605697

相关文章

  • 记录_信号完整性上机报告
    《信号完整性》实验报告实验工程图: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继续对端口进行详细信息扫......
  • CloseableHttpAsyncClient使用代理问题记录
    目录场景背景问题解决过程解决方案总结场景背景项目A部署到现场后,甲方要求调用接口上传某些数据给他们。问题代码很快就开发完成了,但是领导要求必须想办法调用一次测试一次,而且现场没有测试环境(测试当生产用),只能本地使用VPN然后再调用接口测试。VPN本身很多坑就不说了,后面VP......
  • ASP .NET Core 中的请求-响应日志记录
    参考源码:https://download.csdn.net/download/hefeng_aspnet/90084914         记录ASP.NETCorehttp请求和响应是几乎每个.NET开发人员迟早都会面临的常见任务。长期以来,开发团队选择的最流行的方法似乎是编写自定义中间件。但是,既然 .NET6 我们有一个Micr......