1. 程式人生 > 其它 >2021牛客多校 第七場 F xay loves trees (線段樹+括號化序列

2021牛客多校 第七場 F xay loves trees (線段樹+括號化序列

題意:給定兩個樹,求一個最大的點集,使得第一棵樹上成一條鏈並且第二課樹上不互為祖先

思路:賽場上不知道括號化序列這個知識點,所以想不到什麼好辦法能快速處理互為祖先這件事。賽後B站看了題解學會的

括號化序列:根據一棵樹的dfs序,將其入棧與出棧的時間戳記錄下來, 可以發現,每一棵子樹的出入時間必定被根節點包含,如圖;

所以一棵樹的祖先關係就可以轉換成數軸上的一段段區間關係

那麼處理這種區間關係最好的就是線段樹了。

我們先根據第二棵樹,dfs找出括號化序列,然後再遍歷第一棵樹。

遍歷的時候維護一棵線段樹,用於維護當前區間上深度最大的結點。

因為我們要的是連續的鏈,所以如果樹上每一個結點的貢獻就是其向上找最近的衝突點。

程式碼有幾個注意點:1.因為某段區間上的點可能會被pop完,所以要開一個vector來儲存區間上的點,方便回溯與找最後一個點,另外開一個mx陣列,記錄當前區間上的最大值

查詢的時候對於過程中找到的區間,ret取的max值應該是vector裡面的而不是mx裡面的,因為mx會取到不屬於查詢區間的值。

遍歷第一棵樹的時候注意要記錄下來當前衝突的最晚節點。因為產生衝突的不一定是當前節點。

下附程式碼:

  1 #include<bits/stdc++.h>
  2 #define p2 (p<<1)
  3 #define p3 (p<<1|1)
  4 using
namespace std; 5 const int maxn=3e5+5; 6 vector<int> G1[maxn]; 7 vector<int> G2[maxn]; 8 int stackd,dfnl[maxn],dfnr[maxn]; 9 vector<int> tr[maxn<<3]; 10 int mx[maxn<<3]; 11 int res=0,n; 12 int d[maxn]; 13 void dfs1(int x,int pre){ 14 dfnl[x]=++stackd;
15 for (auto y:G2[x]){ 16 if (y!=pre){ 17 dfs1(y,x); 18 } 19 } 20 dfnr[x]=++stackd; 21 } 22 void build(int l,int r,int p){ 23 if (l==r){ 24 mx[p]=0; 25 tr[p].clear(); 26 return ; 27 } 28 int mid=(l+r)>>1; 29 build(l,mid,p2); 30 build(mid+1,r,p3); 31 } 32 void pushup(int l,int r,int p){ 33 mx[p]=0; 34 if (tr[p].size()) mx[p]=*(tr[p].end()-1); 35 if (l<r){ 36 mx[p]=max(mx[p],mx[p2]); 37 mx[p]=max(mx[p],mx[p3]); 38 } 39 } 40 void update(int l,int r,int le,int ri,int p,int val){ 41 if (l==le && r==ri){ 42 if (val>0) tr[p].push_back(d[val]); 43 else tr[p].pop_back(); 44 pushup(l,r,p); 45 return ; 46 } 47 int mid=(l+r)>>1; 48 if (ri<=mid) update(l,mid,le,ri,p2,val); 49 else if (le>mid) update(mid+1,r,le,ri,p3,val); 50 else update(l,mid,le,mid,p2,val),update(mid+1,r,mid+1,ri,p3,val); 51 pushup(l,r,p); 52 } 53 int query(int l,int r,int le,int ri,int p){ 54 if (l==le && r==ri){ 55 return mx[p]; 56 } 57 int mid=(l+r)>>1,ret=0; 58 if (tr[p].size()) ret=*(tr[p].end()-1); 59 if (ri<=mid) ret=max(ret,query(l,mid,le,ri,p2)); 60 else if (le>mid) ret=max(ret,query(mid+1,r,le,ri,p3)); 61 else ret=max(max(query(l,mid,le,mid,p2),query(mid+1,r,mid+1,ri,p3)),ret); 62 return ret; 63 } 64 void dfs2(int x,int dis,int pre){ 65 dis=max(dis,query(1,2*n,dfnl[x],dfnr[x],1)); 66 res=max(res,d[x]-dis); 67 update(1,2*n,dfnl[x],dfnr[x],1,x); 68 for (auto y:G1[x]){ 69 if (y!=pre){ 70 d[y]=d[x]+1; 71 dfs2(y,dis,x); 72 } 73 } 74 update(1,2*n,dfnl[x],dfnr[x],1,-x); 75 } 76 int main(){ 77 int T; 78 scanf("%d",&T); 79 while (T--){ 80 scanf("%d",&n); 81 stackd=0; 82 res=1; 83 for (int i=1; i<=n; i++){ 84 d[i]=0; 85 G1[i].clear(); 86 G2[i].clear(); 87 } 88 d[1]=1; 89 for (int i=1; i<n; i++){ 90 int x,y; 91 scanf("%d%d",&x,&y); 92 G1[x].push_back(y); 93 G1[y].push_back(x); 94 } 95 for (int i=1; i<n; i++){ 96 int x,y; 97 scanf("%d%d",&x,&y); 98 G2[x].push_back(y); 99 G2[y].push_back(x); 100 } 101 dfs1(1,0); 102 build(1,2*n,1); 103 dfs2(1,0,0); 104 printf("%d\n",res); 105 } 106 }
View Code