xay loves tree-dfs序&尺取&线段树
https://ac.nowcoder.com/acm/contest/11258/F
题意:
两棵树结点1到n,要求取最大子集,使第一棵树中任意两个结点之间存在祖孙关系并且是连通的,第二棵树中任意两点之间不存在祖孙关系。
思路:
-
求第二棵树的dfs序,那么第二棵树的连续区间[dfn[i],dfn[i]+siz[i]-1]就是i结点在第二棵树中的子树,可以通过判断j是否在该区间判断j是否是i的子树结点(可以用线段树实现)
-
根据题意易知第一棵树中的结果一定是一条链。那么可以通过滑动窗口遍历每一条链。记录第一棵树中区间在第二棵树中的子树范围,判断结点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 }