D. Country Division
给出一个n(n<2e5)个点n-1条边的树
q组询问
每次将一些点染红,一些点染蓝
问是否能删掉一条边使得红点相互联通,蓝点相互联通,但红蓝点不能相互联通
参考博客
这题当作树上倍增寻找Lca算法的练习题记录
我们求出所有红点LcaRed,所有蓝点LcaBlue,如果所有蓝点不在LcaRed的子树中或者
所有红点不在LcaBlue的子树中,那么就是yes。
这里有几个技巧:
我们不选择两两点找公共祖先,而是直接找dfs序最小的点(即dfs最先遍历到的点)
和dfs序最大的点(即dfs最后遍历到的点)的最近公共祖先
那两个点的公共祖先就是所有红点/蓝点的最近公共祖先
那么由于根节点选择的不同是否对判断结果产生影响?事实是不会
若红点连通块和蓝点连通块联通 那么无论以哪个点作为根节点
必然都不符合条件(如果所有蓝点不在LcaRed的子树中或者所有红点不在LcaBlue的子树中)
反之若以某点为根节点时符合条件(如果所有蓝点不在LcaRed的子树中或者所有红点不在LcaBlue的子树中)
那么任意其他点为根节点时也符合条件
不会证明但是画图大概能感觉到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| #include <bits/stdc++.h> using namespace std; typedef long long ll; #define endl '\n' #define Turnoff std::ios::sync_with_stdio(false) const int Max=2e5+5; const ll Mod=1e9+7;
vector<int>mp[Max]; int cnt=0;
int Dfsin[Max],Dfsout[Max]; int Fa[Max][20],deep[Max]; int Lca(int x,int y){ if(deep[x]<deep[y])swap(x,y); for(int i=19;i>=0;i--){ if(deep[Fa[x][i]]>=deep[y])x=Fa[x][i]; } if(x==y)return x; for(int i=19;i>=0;i--){ if(Fa[x][i]!=Fa[y][i]){ x=Fa[x][i]; y=Fa[y][i]; } } return Fa[x][0]; } void dfs(int now,int fa){ Dfsin[now]=++cnt; deep[now]=deep[fa]+1; Fa[now][0]=fa; for(int i=1;i<20;i++)Fa[now][i]=Fa[Fa[now][i-1]][i-1]; for(auto to:mp[now]){ if(to==fa)continue; dfs(to,now); } Dfsout[now]=cnt; } bool check(int u,vector<int> node){ for(auto i:node){ if(Dfsin[u]<=Dfsin[i]&&Dfsout[u]>=Dfsout[i])return 0; } return 1; } int main(){ int n;cin>>n; for(int i=1;i<n;i++){ int u,v;cin>>u>>v; mp[u].push_back(v); mp[v].push_back(u); } dfs(1,0); int q;cin>>q; while(q--){ int r,b;cin>>r>>b; vector<int>Red,Blue; int Firstvis=0,Lastvis=0; for(int i=0;i<r;i++){ int temp;cin>>temp; Red.push_back(temp); if(!Firstvis||Dfsin[Firstvis]>Dfsin[temp])Firstvis=temp; if(!Lastvis||Dfsin[Lastvis]<Dfsin[temp])Lastvis=temp; } int LcaRed=Lca(Lastvis,Firstvis); Lastvis=0,Firstvis=0; for(int i=0;i<b;i++){ int temp;cin>>temp; Blue.push_back(temp); if(!Firstvis||Dfsin[Firstvis]>Dfsin[temp])Firstvis=temp; if(!Lastvis||Dfsin[Lastvis]<Dfsin[temp])Lastvis=temp; } int LcaBlue=Lca(Lastvis,Firstvis); if(check(LcaBlue,Red))cout<<"YES"<<endl; else if(check(LcaRed,Blue))cout<<"YES"<<endl; else cout<<"NO"<<endl; } }
|