題面
原題連結
思路
我們考慮如何判斷一對 \(T_1,T_2\) 是否合法。
首先,我們可以發現 \(T_2\) 上的邊權只能有至多一組合法解,這是因為對於任意一條邊連線 \(u,v\),它的邊權必然是 \(dis_1(u,v)\),所以事實上我們是沒有許可權給 \(T_2\) 任意賦權的,這樣題目就簡單了一些。
那麼,我們如何判定每一對 \(u,v\) 均滿足 \(dis_1(u,v)=dis_2(u,v)\) 呢?直接跑最短路顯然不現實,那麼就考慮轉化問題了。
假設 \(T_2\) 上 \(u\rightarrow v\) 的簡單路徑依次經過了 \(v_1\sim v_k\)(包括 \(u\) 與 \(v\)),那麼 \(dis_2(u,v)= \sum\limits_{i=1}^{k-1}dis_2(v_i,v_{i+1})\),因為任意 \(u,v\) 均滿足 \(dis_1(u,v)=dis_2(u,v)\),所以 \(dis_2(u,v)=\sum\limits_{i=1}^{k-1}dis_1(v_i,v_{i+1})\),在合法條件下,這一式子必然成立。
而 \(\sum\limits_{i=1}^{k-1}dis_1(v_i,v_{i+1})\) 這個式子的內涵,就是 \(T_1\) 上一條 \(v_1\rightarrow v_2\rightarrow v_3\rightarrow\cdots\rightarrow v_k\) 的非簡單路徑的邊權之和,注意,這裡經過的邊權會被計算多次,經過幾次算幾次。
那麼 \(dis_1(u,v)=dis_2(u,v)\) 就轉化成了 \(dis_1(u,v)=\sum\limits_{i=1}^{k-1}dis_1(v_i,v_{i+1})\),與 \(T_2\) 無關了。
如果上面這個式子滿足,不難想到如果一條邊在左右兩式中貢獻次數不同,其邊權只能為 \(0\)。形式化地說,記在右式中與左式中邊 \(e\) 分別被經過了 \(p_e,q_e\) 次,那麼這充要於對於所有 \(p_e\neq q_e\) 的 \(e\),\(w_e=0\)。
下面我們引出一個重要性質:\(p_e\equiv q_e(\bmod 2)\),並且 \(p_e\ge q_e\),發現 \(p_e\neq q_e\) 充要於 \(p_e\ge 2\),那麼 \(p_e\ge 2\) 的邊就很好刻畫了:它必然在一對簡單路徑 \(i\neq j\),\(path(a_i,a_{i+1})\) 與 \(path(a_j,a_{j+1})\) 的交邊上。
所以,\(dis_1(u,v)=dis_2(u,v)\) 充要於\(\forall 1\le i<j<k,\ path(a_i,a_{i+1}),path(a_j,a_{j+1})\) 相交的部分邊權均為 \(0\)。
更進一步, \((T_1,T_2)\) 合法充要於對所有 \(T_2\) 上的邊二元組 \(e_1\neq e_2\),\(path_1(u_{e_1},v_{e_1}),path_1(u_{e_2},v_{e_2})\) 交的部分邊權均為 \(0\)。
- 必要性:如果存在一對邊二元組 \(e_1\neq e_2\),\(path_1(u_{e_1},v_{e_1}),path_1(u_{e_2},v_{e_2})\) 交的部分邊權不為 \(0\),因為 \(T_2\) 上必然有存在 \(path_2(u,v)\) 內包含 \(e_1,e_2\),那麼 \(dis_1(u,v)\neq dis_2(u,v)\),樹不合法。
- 充分性:讀者自證不難。
然後考慮一個很簡單的轉換,一條邊為兩條路徑的交,那麼它被這兩條路徑覆蓋。
最後,判斷方法就呼之欲出了:對於 \(T_2\) 上的每一條邊 \((u,v)\),將 \(T_1\) 上 \(path_1(u,v)\) 上所有邊覆蓋次數 \(+1\),最後假如 \(T_1\) 上存在邊被覆蓋多次且其邊權不為 \(0\),則不可行。若所有邊均合法,則可行。
實現
不難發現,我們只需要修改所有使得 \((T_1,T_2)\) 不合法的邊就可以了。
更具體地,修改次數就是被覆蓋多次且邊權不為 \(0\) 的 \(T_1\) 上的邊的數量。
如果使用樹上差分計算所有邊的被覆蓋次數,時間複雜度為 \(O(n\log n)\) 的。
同時,考慮到我們只需要判定一條邊是否被覆蓋至少兩次,使用 \(O(n)-O(1)\) LCA 可以做到 \(O(n)\)。當然這並不是必要的,樹上差分已經足以透過這道題了。
程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,T=20;
int n;
int f[N][T+1];
int v[N];
vector<int> ed[N];
int dp[N];
int cf[N];
int ans;
void dfsi(int now){
dp[now]=dp[f[now][0]]+1;
for(auto nxt:ed[now]){
dfsi(nxt);
}
}
void binit(){
for(int t=1;t<=T;t++){
for(int i=1;i<=n;i++){
f[i][t]=f[f[i][t-1]][t-1];
}
}
}
int lca(int a,int b){
if(dp[a]>dp[b])swap(a,b);
for(int t=T;t>=0;t--){
if(dp[f[b][t]]>=dp[a])b=f[b][t];
}
if(a==b)return a;
for(int t=T;t>=0;t--){
if(f[a][t]!=f[b][t]){
a=f[a][t];
b=f[b][t];
}
}
return f[a][0];
}
void dfss(int now){
for(auto nxt:ed[now]){
dfss(nxt);
cf[now]+=cf[nxt];
if(cf[nxt]>1&&v[nxt]>0)ans++;
}
}
void solve(){
cin>>n;
f[1][0]=1;
for(int i=1;i<=n;i++)ed[i].clear();
for(int i=1;i<=n;i++)cf[i]=0;
for(int i=2;i<=n;i++)cin>>f[i][0];
for(int i=2;i<=n;i++){
cin>>v[i];
ed[f[i][0]].push_back(i);
}
dfsi(1);
binit();
for(int i=2,j;i<=n;i++){
cin>>j;
int k=lca(i,j);
cf[k]-=2;
cf[i]++;cf[j]++;
}
ans=0;
dfss(1);
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;cin>>t;
while(t--)solve();
return 0;
}