1. 程式人生 > 實用技巧 >牛客程式設計巔峰賽S2第10場 - 鑽石&王者 C.牛牛的路徑和 (位運算,dfs)

牛客程式設計巔峰賽S2第10場 - 鑽石&王者 C.牛牛的路徑和 (位運算,dfs)

  • 題意:給你節點數為\(n\)的樹,每個節點都有自己的權值,求所有路徑的上的點的權值按位與的和.
  • 題解:題目給的資料很大,我們不能直接去找.因此我們可以列舉二進位制\([1,20]\)的每一位,然後再列舉所有點,看它二進位制對應位置是否滿足條件,之後再去dfs找\(1\)的連通塊即可.
  • 程式碼:
const int N=1e6+10;
class Solution {
public:
    /**
     * 程式碼中的類名、方法名、引數名已經指定,請勿修改,直接返回方法規定的值即可
     * 
     * @param n int整型 點的個數
     * @param u int整型vector 每條邊的起點
     * @param v int整型vector 每條邊的終點
     * @param p int整型vector 每個點的價值
     * @return long長整型
     */

	vector<int> e[N];
	bool st[N];
	long long res=0;
	int cnt[N];

	void dfs(int u,int fa){
		res++;
		st[u]=true;
		for(auto w:e[u]){
			if(st[w] || w==fa || !cnt[w]) continue;
			dfs(w,u);
		}
	}

    long long solve(int n, vector<int>& u, vector<int>& v, vector<int>& p) {
        // write code here
		for(int i=0;i<n-1;++i){
			e[u[i]].push_back(v[i]);
			e[v[i]].push_back(u[i]);
		}
        long long ans=0;
		for(int i=0;i<=20;++i){
			for(int j=0;j<n;++j) ((1<<i)&p[j])?cnt[j]=1:cnt[j]=0;
			memset(st,false,sizeof(st));
			for(int j=0;j<n;++j){
				if(st[j] || cnt[j]==0) continue;
				res=0;
				dfs(j,-1);
				ans+=(res+res*(res-1)/2)*(1<<i);
			}
		}
	
		return ans;
    }
};