1. 程式人生 > 其它 >咕咕的搜尋序列 dfs + 思維

咕咕的搜尋序列 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;
}

別虐記錄