日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

      歡迎訪問 生活随笔!

      生活随笔

      當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

      编程问答

      P6623-[省选联考2020A卷]树【Trie,树上启发式合并】

      發布時間:2023/12/3 编程问答 32 豆豆
      生活随笔 收集整理的這篇文章主要介紹了 P6623-[省选联考2020A卷]树【Trie,树上启发式合并】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

      正題

      題目鏈接:https://www.luogu.com.cn/problem/P6623


      題目大意

      一棵樹,每個節點有一個權值valival_ivali?,定義disi,jdis_{i,j}disi,j?表示iiijjj的距離。

      一個節點xxx的權值定義為該節點子樹中的每個節點yyydisx,y+valjdis_{x,y}+val_{j}disx,y?+valj?的異或和。

      求所有節點的權值和


      解題思路

      對于一個二進制010101串,我們可以用TrieTrieTrie從高位到低位存,我們記錄TrieTrieTrie上每個位置的答案,考慮如何讓整個TrieTrieTrie上的數字+1+1+1

      顯然對于一個000指向的節點,它會變成111,對于111指向的節點,它會變成000并且進位。也就是我們交換左右子樹后再向原來111指向的節點進位。

      這樣我們就實現了一個可以插入數字或者全部+1+1+1來維護答案的數據結構,之后用樹上啟發式合并即可。

      時間復雜度O(nlog?2n)O(n\log^2 n)O(nlog2n)


      codecodecode

      #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=6e5+10,M=27; struct node{int to,next; }a[N]; int n,tot,cnt,ls[N],siz[N],son[N]; int w[N],s[N*M],v[N*M],ch[N*M][2],ed[N*M],z; long long ans; void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot; } void Make(int &x,int k){if(!x){x=++cnt;ch[x][0]=ch[x][1]=s[x]=ed[x]=v[x]=0;}if(!k){s[x]^=1;ed[x]^=1;return;}Make(ch[x][k&1],k>>1);s[x]=s[ch[x][0]]^s[ch[x][1]]^ed[x];v[x]=(v[ch[x][0]]<<1)^((v[ch[x][1]]<<1)|s[ch[x][1]]);return; } void Merge(int x){if(!x){return;}swap(ch[x][0],ch[x][1]);if(ed[x]&&!ch[x][1]){ch[x][1]=++cnt;ch[cnt][0]=ch[cnt][1]=s[cnt]=ed[cnt]=v[cnt]=0;}ed[ch[x][1]]^=ed[x];s[ch[x][1]]^=ed[x];ed[x]=0;Merge(ch[x][0]);s[x]=s[ch[x][0]]^s[ch[x][1]]^ed[x];v[x]=(v[ch[x][0]]<<1)^((v[ch[x][1]]<<1)|s[ch[x][1]]);return; } void dfs(int x){siz[x]=1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;dfs(y);siz[x]+=siz[y];if(siz[y]>siz[son[x]])son[x]=y;}return; } void calc(int x,int dep){Make(z,w[x]+dep);for(int i=ls[x];i;i=a[i].next){int y=a[i].to;calc(y,dep+1);}return; } void solve(int x){for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==son[x])continue;solve(y);}cnt=z=0;if(son[x])solve(son[x]),Merge(z);for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==son[x])continue;calc(y,1);}Make(z,w[x]);ans+=v[1];return; } int main() {freopen("tree2.in","r",stdin);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&w[i]);for(int i=2;i<=n;i++){int x;scanf("%d",&x);addl(x,i);}dfs(1);solve(1);printf("%lld",ans); }

      總結

      以上是生活随笔為你收集整理的P6623-[省选联考2020A卷]树【Trie,树上启发式合并】的全部內容,希望文章能夠幫你解決所遇到的問題。

      如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。