定义边的权值为连接的两点权值的
and
a
n
d
,那么一个连通块所有点的
and
a
n
d
值等于所有边权的
and
a
n
d
值。
枚举答案的
and
a
n
d
值,再枚举权值包含它的所有边,用并查集求出最大连通块就好了。
复杂度为
O(α3logn)
O
(
α
3
log
n
)
。
#include<bits/stdc++.h>
using namespace std;
char nc() {
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
void Read(int& x) {
char c=nc();
for(;c<'0'||c>'9';c=nc());
for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
const int N=100010;
int k,n,m,T,cnt,cur;
int u[N],v[N],f[N],sz[N];
int a[N];
int Res;
long long Ans;
vector<int>g[N];
int Find(int x) {
return f[x]==x?x:f[x]=Find(f[x]);
}
void Un(int x,int y) {
if(a[x]!=cur) a[x]=cur,f[x]=x,sz[x]=1;
if(a[y]!=cur) a[y]=cur,f[y]=y,sz[y]=1;
x=Find(x);y=Find(y);
if(x==y) return;
f[y]=x;sz[x]+=sz[y];
Res=max(Res,sz[x]);
}
int main() {
Read(T);
while(T--) {
Read(n);
for(int i=0;i<n;i++) g[i].clear();
for(int i=1;i<n;i++) {
Read(u[i]);Read(v[i]);
g[u[i]&v[i]].push_back(i);
}
Ans=n;
for(int i=1;i<n;i++) {
++cur;Res=0;
for(int j=i;j<n;j=(j+1)|i)
for(int p=0;p<g[j].size();p++)
Un(u[g[j][p]],v[g[j][p]]);
Ans=max(Ans,1ll*Res*i);
}
printf("%lld\n",Ans);
}
return 0;
}