咕咕的搜索序列 dfs + 思维
作者:互联网
思维
踩坑
1,观察完整的dfs序,即后序遍历,以r为子树的dfs序一定是连续的,且最右边为节点r。
2,故有等式: 设 该树的dfs序为 S, 以r为子树的dfs序的区间为[x, y] 则有 :
S[y] = r, 最右边为点r
y - x + 1 = size[r] 该区间的长度等于子树的大小
3,考虑本题: 如果题中给的dfs序有点被删除了,则没删除的点任满足上述规律,只需忽略被删除的点即可。 如果不满足则必不可能,反之......(我也证明不出来--<-<-<@)。
4,莽了一发,发现大部分样例都能过,说明大体思路是没有问题滴,继续考虑细节问题。
5,
hack 数据: 3 5 4 1
即2号节点被删除了,但是5出现在3 和 4 之间了,显然不可能。
6,出现这种情况的原因是因为2号节点被删除了,故上述算法没考虑以2号节点为根的子树。故只需也考虑被删除的节点即可,被删除节点也应该满足以上的式子。
7,数据大于 1e6 记得关闭 cin 同步,尽量用前向星.
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define fi first
#define se second
#define pb push_back
#define foa(x, y, z) for(int x = (y), ooo = (z); x <= z; ++x)
#define fos(x, y, z) for(int x = (y), ooo = (z); x >= z; --x)
#define ckmax(x, y) ((x) < (y) ? (x) = (y), 1 : 0)
#define ckmin(x, y) ((x) > (y) ? (x) = (y), 1 : 0)
typedef pair<int, int> pii;
typedef long long ll;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
int n, m;
//vector<int> gr[N];
int b[N], p[N];
int flag;
int fl[N], fr[N], g[N];
int h[N], nxt[N], v[N], cnt = 0;
void add(int x, int y)
{
v[++cnt] = y, nxt[cnt] = h[x], h[x] = cnt;
}
void dfs(int r)
{
fl[r] = inf, fr[r] = -1;
g[r] = 0;
if(p[r] != 0) {
fl[r] = p[r];
fr[r] = p[r];
g[r] = 1;
}
for(int i = h[r]; i; i = nxt[i]) {
int x = v[i];
dfs(x);
g[r] += g[x];
ckmin(fl[r], fl[x]);
ckmax(fr[r], fr[x]);
}
if(fr[r] != -1) {
if(p[r] && fr[r] != p[r]) flag = 0;
if(fr[r] - fl[r] + 1 != g[r]) flag = 0;
}
}
void solve()
{
// foa(i, 1, n) gr[i].clear();
cin >> n >> m;
memset(h, 0, sizeof(int) * (n + 5));
foa(i, 2, n) {
int fa;
cin >> fa;
// gr[fa].pb(i);
add(fa, i);
}
memset(p, 0, sizeof(int) * (n + 5));
foa(i, 1, m) {
cin >> b[i];
p[b[i]] = i;
}
flag = 1;
dfs(1);
if(flag) cout << "NOT BAD\n";
else cout << "BAD GUGU\n";
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t;
cin >> t;
while(t--)
solve();
return 0;
}
别虐记录
标签:fr,咕咕,dfs,int,flag,序列,fl,define 来源: https://www.cnblogs.com/hello-acm/p/16229294.html