#include<bits/stdc++.h>#define int long longusingnamespacestd;constintN=2e5+5;intn,ans;intf[N],a[N];vector<int>G[N];set<int>st[N];voiddfs(intu,intpar){st[u].insert(f[u]);for(autov:G[u]){if(v==par)continue;f[v]^=f[u];dfs(v,u);if(st[v].size()>st[u].size()){swap(st[u],st[v]);}}boolok=true;for(autov:G[u]){if(v==par)continue;if(ok==false)continue;for(autoval:st[v]){if(st[u].count(val^a[u])){ok=false;st[u].clear();ans++;break;}}if(ok){for(autoval:st[v]){st[u].insert(val);}}}}signedmain(){cin>>n;for(inti=1;i<=n;i++){cin>>a[i];f[i]=a[i];}for(inti=1;i<n;i++){intu,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}dfs(1,0);cout<<ans<<"\n";}
那就是目前與 i 相連的點中編號最小的點 j,我們把與 i 相連的點都向它連邊,完全圖就可以一步步連好了。考慮正確性,首先,在與 i 相連的點中,最先處理到的肯定是 j,這時,比 j 小的點都已經去旅遊了,比 j 大的點都還在,也都記錄下來了。
【具體實現】:
我們使用 set,因為方便合併,求最小點也快,還可以防止有重邊。我們發現只有 i 連向比自己編號大的點才可能被算貢獻,所以 set 只記錄比自己大的點,比自己小的點都會在自己之前被刪掉,沒有貢獻。合併的時候,採用啟發式合併,兩個中小的那個 set 併入大的 set 裡面,複雜度多個 \(\log n\),總複雜度 \(O(n\log^2 n)\)。答案計算只需要累加目前 i 點的邊數減去一開始的,求變化量就好了。
因為我們發現有很多種顏色要記錄,不能單純使用樹 dp,我們改成使用啟發式合併,紀錄以 u 為根,每種連到 u,且合法的 path 的各種端點的顏色,與他們的數量。在合併的時候記得不要合併跟當前節點顏色一樣的端點,因為他們是連不到更上面的(最多連到 u)。
其實這題也存在線性時間解,我們考慮將 path(s, t) 的貢獻在 s, t 其中一端來計算,具體來說,假設當前我們已經算完子樹之外的各個顏色的個數,我們存在 col 陣列內,當我們目前進入到一個點 u 的時候,以他為「閉合」的一端(也就是另一端在 u 的子樹枝外)的方案數就是 col[c[u]],接著,我們要去遞迴 u 的小孩來解子問題,但不同的是 u 的小孩要將 path 連上來時若顏色恰為 c[u],那依照題目最多就只能連到 c[u],所以此時將 col[c[u]] 設為 1。
#include<bits/stdc++.h>#define int long longusingnamespacestd;vector<int>c;vector<vector<int>>G;vector<map<int,int>>cnt;intans=0;voiddfs(intu,intp){intbst=-1;for(intv:G[u]){if(v==p){continue;}dfs(v,u);if(bst==-1||cnt[bst].size()<cnt[v].size()){bst=v;}}for(intv:G[u]){if(v==p||v==bst){continue;}for(autoit:cnt[v]){intx=it.first,y=it.second;if(x!=c[u]){// 兩端在不同 subtree 的ans+=cnt[bst][x]*1ll*y;}// x == c[u] 還是要記錄,下面會用到cnt[bst][x]+=y;}}if(bst!=-1){swap(cnt[bst],cnt[u]);}// 以 u 作為一端的ans+=cnt[u][c[u]];// resetcnt[u][c[u]]=1;}voidsolve(){intn;cin>>n;c=vector<int>(n);G=vector<vector<int>>(n);for(inti=0;i<n;i++){cin>>c[i];}for(inti=0;i<n-1;i++){inta,b;cin>>a>>b;a--;b--;G[a].push_back(b);G[b].push_back(a);}ans=0;cnt.assign(n,{});dfs(0,-1);cout<<ans<<'\n';}signedmain(){ios_base::sync_with_stdio(false);cin.tie(0);intt;cin>>t;while(t--){solve();}}
#include<bits/stdc++.h>#define int long longusingnamespacestd;vector<int>c;vector<vector<int>>G;intres=0;intcol[200001];voiddfs(intu,intpre){res+=col[c[u]];intnb=col[c[u]];for(intv:G[u]){if(v==pre){continue;}col[c[u]]=1;dfs(v,u);}col[c[u]]=nb+1;}voidsolve(){intn;cin>>n;c=vector<int>(n);G=vector<vector<int>>(n);for(inti=0;i<n;i++){cin>>c[i];}for(inti=0;i<n-1;i++){inta,b;cin>>a>>b;a--;b--;G[a].push_back(b);G[b].push_back(a);}res=0;for(inti=1;i<=n;i++){col[i]=0;}dfs(0,-1);cout<<res<<'\n';}signedmain(){ios_base::sync_with_stdio(false);cin.tie(0);intt;cin>>t;while(t--){solve();}}