2021牛客多校 第七场 F xay loves trees (线段树+括号化序列

题意:给定两个树,求一个最大的点集,使得第一棵树上成一条链并且第二课树上不互为祖先

思路:赛场上不知道括号化序列这个知识点,所以想不到什么好办法能快速处理互为祖先这件事。赛后B站看了题解学会的

括号化序列:根据一棵树的dfs序,将其入栈与出栈的时间戳记录下来, 可以发现,每一棵子树的出入时间必定被根节点包含,如图;2021牛客多校 第七场 F xay loves trees (线段树+括号化序列

 

 所以一棵树的祖先关系就可以转换成数轴上的一段段区间关系

那么处理这种区间关系最好的就是线段树了。

 

我们先根据第二棵树,dfs找出括号化序列,然后再遍历第一棵树。

遍历的时候维护一棵线段树,用于维护当前区间上深度最大的结点。

因为我们要的是连续的链,所以如果树上每一个结点的贡献就是其向上找最近的冲突点。

 

代码有几个注意点:1.因为某段区间上的点可能会被pop完,所以要开一个vector来保存区间上的点,方便回溯与找最后一个点,另外开一个mx数组,记录当前区间上的最大值

查询的时候对于过程中找到的区间,ret取的max值应该是vector里面的而不是mx里面的,因为mx会取到不属于查询区间的值。

遍历第一棵树的时候注意要记录下来当前冲突的最晚节点。因为产生冲突的不一定是当前节点。

 

下附代码:

2021牛客多校 第七场 F xay loves trees (线段树+括号化序列
  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

 

上一篇:[CF755G] PolandBall and Many Other Balls


下一篇:NOIP 模拟 $30\; \rm 毛三琛$