【牛客 - 272B】Xor Path(树上操作,路径异或值)
題干:
給定一棵n個點的樹,每個點有權值。定義表示? 到? 的最短路徑上,所有點的點權異或和。
對于,求所有的異或和。
?
輸入描述:
?第一行一個整數n。
接下來n-1行,每行2個整數u,v,表示u,v之間有一條邊。
第n+1行有n個整數,表示每個點的權值。
輸出描述:
輸出一個整數,表示所有的異或和,其中。?
示例1
輸入
復制
4 1 2 1 3 1 4 1 2 3 4輸出
復制
5說明
?再將這6個數異或起來就可以得到答案5了。
備注:
。題目大意:
? ? ? 每個頂點的點權為Ai,任意兩點路徑上點權異或和為Path(i,j),求所有路徑的Path(i,j)的異或和。
解題報告:
? ?比較套路的一道題,。,算一下每個節點的貢獻就行了。牽扯異或了所以肯定要看是否會有重復操作(因為對這個點進行兩次異或就會使得原結果不變)
一個題解:
考慮每個頂點,有三種情況被用到
1.本身和其他頂點:n-1
2.該頂點上面的頂點(k)和下面的頂點(m)通過該點進行連接:k*m
3.該頂底下面的頂點通過該點進行連接(上面頂點不用的原因是:從上層層下來,已經記錄過。):任意兩個子樹個數相乘之和。(比較難想,,注意一下使用一個技巧: 只有 奇數*奇數 才=奇數,,就方便思考了)
第三種情況直接算會超時,我們需要優化一下,考慮下如果子樹個數為偶數相當于沒有貢獻,所以只要考慮子樹個數為奇數的即可,最后判斷下C(cnt,2)是否為奇數,奇數的話貢獻+1。
AC代碼:(500-700ms第一次交TLE了、、)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair #define fi first #define se second using namespace std; const int MAX = 7e5 + 5; vector<int> vv[MAX]; ll dp[MAX],ans; ll a[MAX]; int n; ll dfs(int cur,int rt) {int up = (int)vv[cur].size();ll tmp,cnt=0,sum=0;for(int i = 0; i<up; i++) {int v = vv[cur][i];if(v == rt) continue;tmp = dfs(v,cur);dp[cur] += tmp; if(tmp%2==1) cnt++;}if((cnt*(cnt-1)/2)%2) sum++;sum+=n-1;sum+= (dp[cur]-1) * (n - dp[cur]); // sum=(sum+(n-1)+(dp[cur]-1)*(n-dp[cur])%2)%2; 用這一行也可以AC、、、if(sum%2==1) ans ^= a[cur];return dp[cur]; } int main() {cin>>n;for(int i = 1,u,v; i<=n-1; i++) {scanf("%d%d",&u,&v);vv[u].pb(v);vv[v].pb(u);} for(int i = 1; i<=n; i++) scanf("%lld",a+i),dp[i]=1;dfs(1,-1);printf("%lld\n",ans);return 0 ;}總結:
? 這題剛開始沒有初始化dp[i]=1,,倒置用注釋和不用注釋的結果不一樣,我當時還在想為什么會不一樣,,因為在哪取模應該都一樣啊,,后來發現是因為dp[cur]-1?那里就變成-1了,,所以先取模和后驅魔結果才會不一樣,,雖然都不是正確結果但是當時句式想研究一下為什么兩種方式會得出不一樣的結果,現在知道了,,并且dp[i]顯然要賦值為1啊。。
再附一個快的飛起的短代碼:(177ms)
#include<bits/stdc++.h> #define ll long long #define N 500010 using namespace std; template <typename T> void read(T &x){x=0;char c=getchar();int fh=1;while (!isdigit(c)){if (c=='-')fh=-1;c=getchar();}while (isdigit(c))x=x*10+c-'0',c=getchar();x*=fh; } struct Info{int nu,ne;}a[N*2]; int b[N],num,x,y,v[N],n; ll si[N],ansn; void jb(int x,int y){a[++num].nu=y;a[num].ne=b[x];b[x]=num;} void dfs(int x,int fa){ll sum=0;si[x]=1;for (int y=b[x];y;y=a[y].ne){if (a[y].nu!=fa){dfs(a[y].nu,x);sum=sum+si[a[y].nu]*si[x];si[x]+=si[a[y].nu];}}sum=sum+si[x]*(n-si[x]);if (sum%2==1)ansn^=v[x]; } int main(){read(n);for (int i=1;i<n;i++){read(x);read(y);jb(x,y);jb(y,x);}for (int i=1;i<=n;i++){read(v[i]);}dfs(1,0);cout<<ansn<<endl;return 0; }std:
#include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar() typedef long long LL; const int N=1e6+5;int n,Ans,Enum,H[N],nxt[N<<1],to[N<<1],A[N],sz[N];inline int read() {int now=0;register char c=gc();for(;!isdigit(c);c=gc());for(;isdigit(c);now=now*10+c-'0',c=gc());return now; } inline void AE(int u,int v) {to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum; } void DFS(int x,int fa) {sz[x]=1;for(int i=H[x],v; i; i=nxt[i])if((v=to[i])!=fa) DFS(v,x), sz[x]+=sz[v];LL tmp=n-sz[x];//不經過x的子樹的路徑for(int s=n-sz[x]+1,i=H[x],v; i; i=nxt[i])if((v=to[i])!=fa) tmp+=1ll*s*sz[v], s+=sz[v];//經過v這個孩子節點的 那一串子樹的。再累加。(話說,,為啥不會爆longlong呢?)if(tmp&1) Ans^=A[x]; } int main() {n=read();for(int i=1; i<n; ++i) AE(read(),read());for(int i=1; i<=n; ++i) A[i]=read();DFS(1,1), printf("%d\n",Ans);fclose(stdin), fclose(stdout);return 0; }?
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【牛客 - 272B】Xor Path(树上操作,路径异或值)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4.48亿!广东彩票史上第一大奖诞生 仅
- 下一篇: 信用卡申请卡片未核发 意味着卡片还没有寄