题解 主仆见证了 Hobo 的离别
题面里说每个元件只会被融合一次,但想着想着题就忘了这个条件了……
首先题意可以转化到图上,即(以只考虑并为例)要求 \(x\) 是 \(y\) 的祖先或 \(x, y\) 之间由 \(k=1\) 的边相连
然后觉得是个有向图,判祖先得离线了用bitset挺麻烦的就跑路了
然而原图实际上是棵树……
- 树上判断两个点是否有祖孙关系:可以用dfs序是否存在包含关系判断
- 树上判断有祖先关系的点是否恰好由某一类边相连:可以对每一类边分别建立并查集,记录当前集合中深度最浅的点,判断与较浅的点的深度就可以了
求出lca的话也可以拓展到树上任意两点
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 500010
#define ll long long
#define pb push_back
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
bitset<10010> s[5010];
namespace force{
int tot;
bool all_one=1;
void solve() {
// cout<<double(sizeof(s))/1024/1024<<endl;
tot=n;
for (int i=1; i<=n; ++i) s[i][i]=1;
for (int i=1,op,k,x,y; i<=m; ++i) {
if (read()&1) {
x=read(); y=read();
if (all_one || n>2010) puts((x&y)==x?"1":"0");
else {
if (x<=y) puts((x&y)==x?"1":"0");
else printf("%d\n", rand()&1);
}
}
else {
op=read(); k=read(); ++tot;
if (k!=1) all_one=0;
if (op&1) {
for (int j=1; j<=k; ++j) s[tot]|=s[read()];
// s[tot][tot]=1;
}
else {
s[tot]=s[read()];
for (int j=1; j<k; ++j) s[tot]&=s[read()];
// s[tot][tot]=1;
}
}
}
// cout<<s[5]<<endl;
exit(0);
}
}
namespace task{
int head[N], size, dsua[N], dsuo[N], dep[N], cnt[N], in[N], out[N], mdepa[N], mdepo[N], now, tot;
vector<int> v[N];
int tp[N], op[N], x[N], y[N];
struct edge{int to, next;}e[N];
inline void add(int s, int t) {e[++size].to=t; e[size].next=head[s]; head[s]=size;}
inline int finda(int p) {return dsua[p]==p?p:dsua[p]=finda(dsua[p]);}
inline int findo(int p) {return dsuo[p]==p?p:dsuo[p]=findo(dsuo[p]);}
inline void unia(int a, int b) {a=finda(a); b=finda(b); mdepa[b]=min(mdepa[b], mdepa[a]); dsua[a]=b;}
inline void unio(int a, int b) {a=findo(a); b=findo(b); mdepo[b]=min(mdepo[b], mdepo[a]); dsuo[a]=b;}
void dfs(int u) {
// cout<<"dfs: "<<u<<endl;
in[u]=++now;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
dep[v]=dep[u]+1;
dfs(v);
}
out[u]=++now;
}
void solve() {
tot=n;
memset(head, -1, sizeof(head));
for (int i=1,k; i<=m; ++i) {
tp[i]=read();
if (tp[i]&1) x[i]=read(), y[i]=read();
else {
op[i]=read(); k=read(); ++tot;
for (int j=1,t; j<=k; ++j) {
v[i].pb(t=read());
add(tot, t); ++cnt[t];
}
}
}
++tot;
// cout<<"tot: "<<tot<<endl;
for (int i=1; i<tot; ++i) if (!cnt[i]) add(tot, i);
dep[tot]=1; dfs(tot); now=n;
// cout<<"dep: "; for (int i=1; i<=tot; ++i) cout<<dep[i]<<' '; cout<<endl;
for (int i=1; i<=tot; ++i) dsua[i]=dsuo[i]=i, mdepa[i]=mdepo[i]=dep[i];
for (int i=1; i<=m; ++i) {
if (tp[i]&1) {
// cout<<"xy: "<<x[i]<<' '<<y[i]<<' '<<in[x[i]]<<' '<<out[x[i]]<<' '<<in[y[i]]<<' '<<out[y[i]]<<endl;
// cout<<"mdep: "<<mdepo[findo(x[i])]<<endl;
if (x[i]==y[i]) puts("1");
else if (in[x[i]]<in[y[i]] && out[y[i]]<out[x[i]]) {
puts(mdepa[finda(y[i])]<=dep[x[i]]?"1":"0");
}
else if (in[y[i]]<in[x[i]] && out[x[i]]<out[y[i]]) {
puts(mdepo[findo(x[i])]<=dep[y[i]]?"1":"0");
}
else puts("0");
}
else {
++now;
if (v[i].size()==1) unia(now, v[i][0]), unio(now, v[i][0]);
else {
if (op[i]&1) for (auto j:v[i]) unio(now, j);
else for (auto j:v[i]) unia(now, j);
}
}
}
}
}
signed main()
{
freopen("friendship.in", "r", stdin);
freopen("friendship.out", "w", stdout);
random_device(seed);
srand(seed());
n=read(); m=read();
// force::solve();
task::solve();
return 0;
}