首页 > 其他分享 >跑步爱天天 题解

跑步爱天天 题解

时间:2024-07-21 15:39:51浏览次数:7  
标签:dpt int 题解 include 警卫 天天 fa 跑步 now

题意简述

一棵以 \(1\) 为根的树,儿子间有先后顺序。初始每个结点上有一个警卫,警卫按照深度优先遍历其子树,儿子间的先后顺序体现在这里,回到起始点后开始新一轮的遍历。yzh 想要从 \(S\) 走到 \(1\),请问她会在路上遇到多少警卫(\(S\) 点的也算)。

题目分析

法 \(1\)

先来讲一讲我考场上的想法。

首先警卫之间互不干扰,所以分别考虑 \(S \sim 1\) 路径上每一个警卫即可。

发现遇到警卫无非两种情况:相向的双向奔赴、同向的同流合污,即警卫向下走遇到人、警卫向上走遇到人。当然还有 \(S\) 点的特殊情况。见下图。

进一步发现,如果和某一个警卫在一条边上擦肩而过,那么之后就不可能再相遇了,因为至少会相差一步。所以题目中说的循环遍历是幌子。

对于 \(1 \sim S\) 路径上的一点 \(u\),不妨设 \(f[u]\) 表示按顺序遍历完左边所有点并回来的需要时刻。不难发现,由于每条边都贡献了来回的 \(2\) 次,这就是左边边数的两倍。不妨再设 \(g\) 是 \(f\) 在链上的前缀和。

考虑警卫 \(u\),假设和 yzh 相遇在点 \(w\),接下来分别讨论两种情况。

双向奔赴

\(u\) 消耗的时间是 \(dpt[w] - dpt[u] + f[u \ldots fa_w]\),yzh 消耗的时间是 \(dpt[S] - dpt[w]\)。所以有:

\[\begin{aligned} dpt[w] - dpt[u] + f[u \ldots fa_w] &= dpt[S] - dpt[w] \\ dpt[w] - dpt[u] + g[fa_w] - g[fa_u] &= dpt[S] - dpt[w] \\ 2 dpt[w] + g[fa_w] &= dpt[u] + dpt[S] + g[fa_u] \\ \end{aligned} \]

不妨把 \(w\) 变为其在链上的孩子。

\[dpt[w] + g[w] = dpt[u] + dpt[S] + g[fa_u] - 2 \]

这一个从 \(S\) 向上回溯的时候,用数据结构维护等号左边,查询等号右边并累加答案。

同流合污

这里注意到在 \(w\) 相遇时左边的点不一定全部访问完,可能只是访问了一部分,记这个一部分为 \(p\)。

\[\begin{aligned} dpt[w] - dpt[u] + f[u ... fa_w] + p &= dpt[S] - dpt[w] \\ 2 dpt[w] + g[fa_w] + p &= dpt[S] + g[fa_u] + dpt[u] \end{aligned} \]

同样回溯的时候能够维护并计算。

时间复杂度 \(\Theta(n)\),但是偷懒用 map 多一个 \(\log\)。

法 \(2\)

很容易想到欧拉序,并且欧拉序上两点间长度就是这两个状态之间的时间间隔。

那么先深搜预处理出每个点在欧拉序上的起点和后一个出现位置。

先把 \(1 \sim S\) 路径上的点在欧拉序上起点打个标记。再枚举在那个点的哪个状态相遇。yzh 到达这个点的步数是确定的,那么我们就能够推出警卫的初始位置。如果这个位置有标记,那么答案加一,并清空标记。

注意到有个小优化:预处理的时候访问到 \(S\) 就可以不用继续搜了。

很简单的做法,时间复杂度 \(\Theta(n)\),常数很小。

代码

法 \(1\)

// #pragma GCC optimize(3)
// #pragma GCC optimize("Ofast", "inline", "-ffast-math")
// #pragma GCC target("avx", "sse2", "sse3", "sse4", "mmx")
#include <iostream>
#include <cstdio>
#define debug(a) cerr << "Line: " << __LINE__ << " " << #a << endl
#define print(a) cerr << #a << "=" << (a) << endl
#define file(a) freopen(#a".in", "r", stdin), freopen(#a".out", "w", stdout)
#define main Main(); signed main() { return ios::sync_with_stdio(0), cin.tie(0), Main(); } signed Main
using namespace std;
 
#include <vector>
#include <unordered_map>
#include <cstring>
 
#include <cctype>
#define P(a) while(a isdigit(c=getchar()))
inline void read(int &x){int c;P(!);x=c-48;P()x=x*10+c-48;}
 
int n, S, ans;
vector<int> edge[500010];
int dpt[500010], f[500010], g[500010];
bool ed;
 
unordered_map<int, bool> mm, aa;
 
void dfs(int now, int fa) {
	f[now] = 0;
	if (now == S) return ed = true, void();
    vector<int> ttt;
	for (const auto& to: edge[now]) {
		dpt[to] = dpt[now] + 1;
        g[to] = g[now] + f[now];
		dfs(to, now);
		if (!ed) f[now] += f[to] + 2, ttt.push_back(f[now]);
		else break;
	}
    if (ed) {
        g[now] += f[now];
        for (const auto& x: ttt)
            aa[2 * dpt[now] + g[fa] + f[fa] + x] = true;
        mm[2 * dpt[now] + g[now]] = true;
        if (mm.count(dpt[S] - 2 + g[fa] + f[fa] + dpt[now])) ++ans;
        else if (aa.count(dpt[S] + dpt[now] + g[fa] + f[fa])) ++ans;
    }
}
 
void solve() {
	read(n);
	for (int i = 1, k, v; i <= n; ++i)
		for (read(k), edge[i].clear(); k--; read(v), edge[i].push_back(v));
	read(S), ed = false, mm.clear(), aa.clear(), ans = 1;
	g[1] = 0, dfs(1, 0), printf("%d\n", ans);
}
 
signed main() {
	int t; read(t);
	while (t--) solve();
	return 0;
}

法 \(2\)

最优解,\(890\) ms。

#include <cstdio>
#include <cstring>
using namespace std;

namespace Fast{
	constexpr const int MAX = 1 << 26, yzh_i_love_you = 1314520736;
	char buf[MAX], *p = buf;
	#define getchar() (*p++)
	constexpr inline bool isdigit(const char c) { return c >= '0' && c <= '9'; }
	inline void read(int &x){
		x = 0; char c = 0;
		for (;!isdigit(c); c = getchar());
		for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
	}
}
using namespace Fast;

struct Graph{
	struct node{
		int to, pre;
	} edge[500010 << 1];
	int eid, head[500010], tail[500010];
	inline void add(int u, int v){
		edge[++eid] = {v, 0};
		(head[u] ? edge[head[u]].pre : tail[u]) = eid;
		head[u] = eid;
	}
	inline node & operator [] (const int x){
		return edge[x];
	}
} xym;

int n, S, fa[500010], ans;
int st[500010], nxt[500010 << 1], timer;
bool ed, mark[500010 << 1];

void dfs(int now) {
	int pre = st[now] = ++timer;
	if (now == S) {
		ed = true;
	} else {
		for (register int i = xym.tail[now], to; to = xym[i].to, i; i = xym[i].pre) {
			dfs(to);
			if (ed) break;
			nxt[pre] = ++timer, pre = timer;
		}
	}
	nxt[pre] = -1;
}

void solve() {
	read(n), xym.eid = ans = timer = ed = 0;
	for (register int i = 1, k, v; i <= n; ++i)
		for (read(k), xym.head[i] = xym.tail[i] = 0; k--; read(v), xym.add(i, v), fa[v] = i);
	read(S), dfs(1), memset(mark, 0x00, timer + 1);
	for (register int i = S; i; i = fa[i]) mark[st[i]] = true;
	for (register int step = 0; S; S = fa[S], ++step)
		for (register int i = st[S]; ~i; i = nxt[i]) if (i > step) {
			ans += mark[i - step];
			mark[i - step] = false;
		}
	printf("%d\n", ans);
}

signed main() {
	fread(buf, 1, MAX, stdin);
	int t; read(t);
	while (t--) solve();
	return 0;
}

标签:dpt,int,题解,include,警卫,天天,fa,跑步,now
From: https://www.cnblogs.com/XuYueming/p/18314455

相关文章

  • 题解:Codeforces Round 960 (Div. 2) D
    D.GridPuzzletimelimitpertest:2secondsmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputYouaregivenanarray\(a\)ofsize\(n\).Thereisan\(n\timesn\)grid.Inthe\(i\)-throw,thefirst\(a_i\)......
  • 【2024最新华为OD-C/D卷试题汇总】[支持在线评测] LYA的生日派对座位安排(200分) - 三
    ......
  • 题解:Codeforces Round 960 (Div. 2) C
    C.MadMADSumtimelimitpertest:2secondsmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputWedefinethe\(\operatorname{MAD}\)(MaximumAppearingDuplicate)inanarrayasthelargestnumberthatappearsatleast......
  • NOI2024 集合 题解
    给个链接:集合。很神秘的题目。基本上看到之后就可以想到哈希。首先想到一个比较神秘的暴力。就是对于每个询问,扫一遍所有\(a\)中的数出现的位置,把它弄成一个哈希值(具体怎么弄随意)存到set里,然后看看是不是和\(b\)中的数出现的位置这样操作后的集合完全相等。事实上就是判断......
  • B3956 [GESP202403 三级] 字母求和 题解
    B3956[GESP202403三级]字母求和题解当时在考试,3分钟A了,结果第二题T了。#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+2;constintN1=1e3+2;typedeflonglongll;typedefunsignedlonglongull;#definefo(i,n,m)for(inti=n;i<=m;i++)......
  • 【科大讯飞笔试题汇总】2024-07-20-科大讯飞秋招提前批(研发岗)-三语言题解(Cpp/Java/
    ......
  • 题解:Codeforces Round 960 (Div. 2) B
    B.ArrayCrafttimelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputForanarray\(b\)ofsize\(m\),wedefine:themaximumprefixpositionof\(b\)isthesmallestindex\(i\)thatsat......
  • 洛谷 P1162 填涂颜色题解
    题目链接填涂颜色题目描述由数字\(0\)组成的方阵中,有一任意形状的由数字\(1\)构成的闭合圈。现要求把闭合圈内的所有空间都填写成\(2\)。例如:\(6\times6\)的方阵(\(n=6\)),涂色前和涂色后的方阵如下:如果从某个\(0\)出发,只向上下左右\(4\)个方向移动且仅经过其他\(0\)......
  • 题解:Codeforces Round 960 (Div. 2) A
    A.SubmissionBaittimelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputAliceandBobareplayingagameinanarray\(a\)ofsize\(n\).Theytaketurnstodooperations,withAlicestarting......
  • [题解]P4166 [SCOI2007] 最大土地面积
    P4166[SCOI2007]最大土地面积解法\(1\)-\(O(n^2)\)我们运用调整法,可以证明这个四边形的\(4\)个顶点一定都在凸包的顶点上,具体来说:\(\textbf{Proof:}\)首先我们知道,凸包内,到某条直线距离最大的点一定包括\(1\)个顶点。接下来我们考虑一个凸包内的四边形:我们过它的对角......