xay loves tree-dfs序&尺取&线段树

https://ac.nowcoder.com/acm/contest/11258/F
题意:

两棵树结点1n,要求取最大子集,使第一棵树中任意两个结点之间存在祖孙关系并且是连通的,第二棵树中任意两点之间不存在祖孙关系。

思路:
  1. 求第二棵树的dfs,那么第二棵树的连续区间[dfn[i],dfn[i]+siz[i]-1]就是i结点在第二棵树中的子树,可以通过判断j是否在该区间判断j是否是i的子树结点(可以用线段树实现)

  2. 根据题意易知第一棵树中的结果一定是一条链。那么可以通过滑动窗口遍历每一条链。记录第一棵树中区间在第二棵树中的子树范围,判断结点i是否可以加入区间的时候,只需要判断i子树范围内是否被记录过。

代码:
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 
  5 const int mx=3e5+10;
  6 
  7 int siz[mx], dfn[mx], dfnid;
  8 int n, ans;
  9 int li[mx];
 10 
 11 struct edge{
 12     int v, nex;
 13     edge(){}
 14     edge(int v, int nex):v(v),nex(nex){}
 15 }e[2][mx<<1];
 16 int head[2][mx], cnt[2];
 17 
 18 struct node{
 19     int l, r, sum, lazy, gs;
 20     node(){}
 21     node(int l, int r):l(l),r(r){sum=lazy=0;gs=r-l+1;}
 22 }nos[mx<<2];
 23 int rt=1;
 24 
 25 
 26 void build(int c, int l, int r){
 27     nos[c]=node(l,r);
 28     if(l == r)return;
 29     int mid=(l+r)>>1;
 30     build(c<<1,l,mid);build(c<<1|1,mid+1,r);
 31 }
 32 
 33 void pushdown(int c){
 34     int ls=c<<1,rs=c<<1|1;
 35     nos[ls].lazy+=nos[c].lazy;
 36     nos[rs].lazy+=nos[c].lazy;
 37     nos[ls].sum+=nos[c].lazy*nos[ls].gs;
 38     nos[rs].sum+=nos[c].lazy*nos[rs].gs;
 39     nos[c].lazy=0;
 40 }
 41 void pushup(int c){
 42     int ls=c<<1,rs=c<<1|1;
 43     nos[c].sum=nos[ls].sum+nos[rs].sum;
 44 }
 45 
 46 void changeVal(int c, int L, int R, int val){
 47     int l=nos[c].l, r=nos[c].r;
 48     if(L<=l && r<=R){
 49         nos[c].sum+=val*nos[c].gs;
 50         nos[c].lazy+=val;
 51         return;
 52     }
 53     pushdown(c);
 54     int mid=(l+r)>>1;
 55     if(L<=mid)changeVal(c<<1,L,R,val);
 56     if(R>mid)changeVal(c<<1|1,L,R,val);
 57     pushup(c);
 58 }
 59 
 60 bool query(int c, int L, int R){//查询[L,R]区间的和是否为0
 61     int l=nos[c].l, r=nos[c].r;
 62     if(L<=l && r<=R){
 63         return nos[c].sum == 0;
 64     }
 65     pushdown(c);
 66     int mid=(l+r)>>1;
 67     bool tmp=true;
 68     if(L<=mid) tmp=tmp && query(c<<1,L,R);
 69     if(R>mid) tmp=tmp && query(c<<1|1,L,R);
 70     pushup(c);
 71     return tmp;
 72 }
 73 
 74 void add(int u, int v, int id){
 75     cnt[id]++;
 76     e[id][cnt[id]]=edge(v,head[id][u]);
 77     head[id][u]=cnt[id];
 78 }
 79 
 80 void dfs1(int c, int fa){
 81     dfn[c]=++dfnid;
 82     siz[c]=1;
 83     int xh=1;
 84     for(int i=head[xh][c];i!=-1;i=e[xh][i].nex){
 85         int id=e[xh][i].v;
 86         if(id == fa) continue;
 87         dfs1(id, c);
 88         siz[c]+=siz[id];
 89     }
 90 }
 91 
 92 void dfs0(int c, int dfn0, int L, int fa){//L表示开始区域 包括L
 93     int Lbef=L;
 94     while(query(rt,dfn[c], dfn[c]+siz[c]-1) == false){
 95         int id=li[L];
 96         changeVal(rt,dfn[id],dfn[id]+siz[id]-1,-1);
 97         L++;
 98     }
 99     changeVal(rt,dfn[c],dfn[c]+siz[c]-1,1);
100     li[dfn0]=c;
101     ans=max(ans,dfn0-L+1);
102     int xh=0;
103     for(int i=head[xh][c];i!=-1;i=e[xh][i].nex){
104         int id=e[xh][i].v;
105         if(id == fa) continue;
106         dfs0(id,dfn0+1,L, c);
107     }
108     changeVal(rt,dfn[c],dfn[c]+siz[c]-1,-1);
109     while(L!=Lbef){
110         L--;
111         int id=li[L];
112         changeVal(rt,dfn[id],dfn[id]+siz[id]-1,1);
113     }
114 }
115 void solve(){
116     memset(head,-1,sizeof(head));
117     cnt[0]=cnt[1]=0;
118     dfnid=ans=0;
119 
120     scanf("%d", &n);
121     int u, v;
122     for(int i=1;i<=n-1;i++){
123         scanf("%d %d", &u, &v);
124         add(u,v,0);
125         add(v,u,0);
126     }
127     for(int i=1;i<=n-1;i++){
128         scanf("%d %d", &u, &v);
129         add(u,v,1);
130         add(v,u,1);
131     }
132 
133     dfs1(1, -1);
134     build(rt,1,n);
135 
136     dfs0(rt,1,1, -1);
137     printf("%d\n", ans);
138 }
139 
140 int main(){
141     int t;
142     scanf("%d", &t);
143     while(t--)
144         solve();
145     return 0;
146 }
View Code

 

posted @ 2021-09-08 21:31  反射狐  阅读(44)  评论(0编辑  收藏  举报